Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
@bitovi/querystring-parser
Advanced tools
![Tests Workflow Status](https://github.com/bitovi/querystring-parser/actions/workflows/tests.yml/badge.svg?branch=main) [![Join our Slack](https://img.shields.io/badge/slack-join%20chat-611f69.svg)](https://www.bitovi.com/community/slack?utm_source=badge
Consider the following situation:
?filter[start_date][$gt]=2020-01-01
?sort=-date,name&page[number]=1&page[size]=5
?fields[articles]=title,body&fields[people]=name
npm install @bitovi/querystring-parser
If you plan to use this library with Objection or Sequelize, do not install @bitovi/querystring-parser
. Instead, install either:
const querystringParser = require("@bitovi/querystring-parser");
const { page } = querystringParser.parse("page[number]=1&page[size]=10");
console.log(page.number); // --> 1
console.log(page.size); // --> 10
The parsed results of the sort
query parameters are stored in the sort
property.
The value of the sort
property is an array of "sort field" objects. Each "sort field" object includes a field name and a sort direction.
Reference: JSON:API - Sorting
const { sort } = querystringParser.parse("sort=-date,name");
console.log(sort[0]); // --> { field: 'date', direction: 'DESC' }
console.log(sort[1]); // --> { field: 'name', direction: 'ASC' }
The parsed results of the page
query parameters are stored in the page
property. The value of the page
property is an object which has 2 keys: number
and size
.
Reference: JSON:API - Pagination
const { page } = querystringParser.parse("page[number]=1&page[size]=10");
console.log(page.number); // --> 1
console.log(page.size); // --> 10
The parsed results of the include
query parameter is stored in the include
property. The value of the include
property is an array of "relationship paths".
Reference: JSON:API - Inclusion of Related Resources
const { include } = querystringParser.parse(
"include=children.movies.actors.children,children.movies.actors.pets,children.pets,pets"
);
console.log(include[0]); // --> 'children.movies.actors.children'
console.log(include[1]); // --> 'children.movies.actors.pets'
console.log(include[2]); // --> 'children.pets'
console.log(include[3]); // --> 'pets'
The parsed results of the fields[TYPE]
query parameters are stored in the fields
property. The value of the fields
property is an object. For each key-value pair in that object, the key is the name of a type and the value is an array of fields for that type.
Reference: JSON:API - Sparse Fieldsets
const { fields } = querystringParser.parse(
"fields[articles]=title,body&fields[people]=name"
);
console.log(fields.articles); // --> [ 'title', 'body' ]
console.log(fields.people); // --> [ 'name' ]
The parsed results of the filter
query parameters are stored in the filter
property. There are 2 "styles" of querystring filters that are supported. "MongoDB-Style" and "IBM-Style". Though they have their own conventions, they both produce the same kind of output. You can use both of these styles if you want, but not in the same querystring.
The MongoDB-Style is based off of the MongoDB comparison query operators.
Querystring Filter | Parsed Output |
---|---|
filter[name]=brad | { LIKE: [ '#name', '%brad%' ] } |
filter[name][$eq]=mike | { '=': [ '#name', 'mike' ] } |
filter[age][$gt]=21 | { '>': [ '#age', 21 ] } |
filter[born][$lte]=2020-01-01 | { '<=': [ '#born', '2020-01-01' ] } |
filter[score][$eq]=null | { 'IS NULL': '#score' } |
filter[name][$in]=michael,brad | { IN: [ '#name', 'michael', 'brad' ] } |
Below is the full list of MongoDB-Style operators and their compatible value types.
Operator | strings | numbers | dates | nulls | arrays |
---|---|---|---|---|---|
$eq | ✅ | ✅ | ✅ | ✅ | ❌ |
$ne | ✅ | ✅ | ✅ | ✅ | ❌ |
$gt | ✅ | ✅ | ✅ | ❌ | ❌ |
$gte | ✅ | ✅ | ✅ | ❌ | ❌ |
$lt | ✅ | ✅ | ✅ | ❌ | ❌ |
$lte | ✅ | ✅ | ✅ | ❌ | ❌ |
ilike | ✅ | ❌ | ❌ | ❌ | ❌ |
$in | ✅ | ✅ | ✅ | ✅ | ✅ |
$nin | ✅ | ✅ | ✅ | ✅ | ✅ |
MongoDB-Style filters do not require explicit operators. In many cases, the value type is enough for the parser to infer which operator to use. The examples below demonstrate operator inference for each value type.
Value Type | Example | Output |
---|---|---|
string | filter[name]=lisa | { LIKE: [ '#name', '%lisa%' ] } |
number | filter[age]=25 | { '=': [ '#age', 25 ] } |
date | filter[born]=2020-01-01 | { '=': [ '#born', '2020-01-01' ] } |
null | filter[score]=null | { 'IS NULL': '#score' } |
array | filter[name]=mike,brad | { IN: [ '#name', 'mike', 'brad' ] } |
The following examples demonstrate how array values may be specified.
filter[age][$in]=24&filter[age][$in]=25&filter[age][$in]=26
,
):
filter[age][$in]=24,25,26
Both styles will result in the same output:
{ IN: [ '#age', 24, 25, 26 ] }
MongoDB-Style filters do not directly support higher-order operators (AND
/ OR
/ NOT
). However, if multiple filters are present in the query string then they will be joined together in an AND
fashion.
// example of 2 filters getting "AND"-ed together into a compound filter
const { filter } = querystringParser.parse("filter[name]=mike&filter[age]=25");
expect(filter).toEqual({
AND: [
{ LIKE: ["#name", "%mike%"] },
{ "=": ["#age", 25] }
]
});
The IBM-Style is based off of the jsonapi.net filtering specification.
Querystring Filter | Parsed Output |
---|---|
filter=contains(name,'brad') | { LIKE: [ '#name', '%brad%' ] } |
filter=equals(name,'mike') | { '=': [ '#name', 'mike' ] } |
filter=greaterThan(age,'25') | { '>': [ '#age', 25 ] } |
filter=lessOrEqual(born,'2020-01-01') | { '<=': [ '#born', '2020-01-01' ] } |
filter=any(name,'brad','mike') | { IN: [ '#name', 'brad', 'mike' ] } |
filter=equals(score,null) | { 'IS NULL': '#score' } |
filter=not(equals(age,'25')) | { NOT: { "=": ["#age", 25] } } |
filter=and(any(age,'10','20'),equals(name,'mike')) | { AND: [{ IN: ["#age", 10, 20] }, { "=": ["#name", "mike"] }] } |
filter=or(any(age,'10','20'),equals(name,'mike')) | { OR: [{ IN: ["#age", 10, 20] }, { "=": ["#name", "mike"] }] } |
Below is the full list of IBM-Style operators and their compatible value types.
Operator | strings | numbers | dates | attribute refs | nulls | nested operators |
---|---|---|---|---|---|---|
equals | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
greaterThan | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
greaterOrEqual | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
lessThan | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
lessOrEqual | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
contains | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
startsWith | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
endsWith | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
any | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
not | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
and | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
or | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
Some of the IBM-Style operators can directly compare 2 different attributes (or "columns").
In the example below, wins
and losses
are attribute references (as opposed to constant values like 'emily'
or '22'
).
By convention, attribute references are prefixed with a '#' in the parsed output to distinguish them from constant values.
// example attribute references
const { filter } = querystringParser.parse("filter=greaterThan(wins,losses)");
expect(filter).toEqual({ ">": ["#wins", "#losses"] });
IBM-Style filters directly support higher-order operators (AND
/ OR
/ NOT
). On top of that, if multiple filters are present in the query string then they will be joined together in an OR
fashion.
// example of 2 filters getting "OR"-ed together into a compound filter
const { filter } = querystringParser.parse("filter=contains(name,'mike')&filter=equals(age,'25')");
expect(filter).toEqual({
OR: [
{ LIKE: ["#name", "%mike%"] },
{ "=": ["#age", 25] }
]
});
See CONTRIBUTING.md
FAQs
![Tests Workflow Status](https://github.com/bitovi/querystring-parser/actions/workflows/tests.yml/badge.svg?branch=main) [![Join our Slack](https://img.shields.io/badge/slack-join%20chat-611f69.svg)](https://www.bitovi.com/community/slack?utm_source=badge
We found that @bitovi/querystring-parser demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 15 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.