Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/TRUEPIC/queryql

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!
https://github.com/TRUEPIC/queryql

api filter filtering knex orm page pagination qs query querystring rest sort sorting

Last synced: about 2 months ago
JSON representation

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Awesome Lists containing this project

README

        

# QueryQL

[![npm](https://img.shields.io/npm/v/@truepic/queryql?color=0f4484)](https://www.npmjs.com/package/@truepic/queryql)
![GitHub Actions](https://github.com/TRUEPIC/queryql/actions/workflows/ci.yml/badge.svg)
![piratepx](https://app.piratepx.com/ship?p=e91ddd1b-31ad-4c36-b03e-be4a1e9a7678&i=queryql)

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js
REST API through your old friend: the query string!
[Read our introductory article](https://medium.com/truepicinc/queryql-easily-add-filtering-sorting-and-pagination-to-your-node-js-rest-api-9222135c93ae)
to learn more about why we wrote it and the problems it solves at
[Truepic](https://truepic.com).

QueryQL works with any Node.js web framework (be it Express, Koa, etc.),
supports any query builder / ORM through _adapters_, and allows for custom
_validators_ so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

- Adapter: [Knex](https://knexjs.org/) (works with
[Objection.js](https://vincit.github.io/objection.js) and other ORMs that use
Knex)
- Validator: [Joi](https://github.com/hapijs/joi)

## Installation

```bash
npm install @truepic/queryql
```

## Getting Started

QueryQL takes a parsed query string (like Express' `req.query`) and translates
it into the appropriate function calls that your query builder / ORM understands
to filter, sort, and paginate the records.

(Make sure your framework uses a query string parser that supports nested
objects. Node.js's native
[`querystring`](https://nodejs.org/api/querystring.html) module _does not_, but
a package like [qs](https://github.com/ljharb/qs) does. It's usually a simple
config change to switch.)

Let's consider an example to illustrate:

```
/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
```

```js
{
filter: {
id: {
in: [2, 3],
},
status: 'open',
},
sort: 'name',
page: {
size: 10,
},
}
```

To support this query, QueryQL only requires you to define (whitelist) what's
allowed through what we call a _querier_. Here's how one might look for the
`/images` endpoint:

```js
const QueryQL = require('@truepic/queryql')

class ImageQuerier extends QueryQL {
defineSchema(schema) {
schema.filter('id', 'in')
schema.filter('status', '=')
schema.sort('name')
schema.page()
}
}
```

With your querier defined, you can now call it in your router / controller.
Here's how it might look in an Express route:

```js
app.get('/images', async (req, res, next) => {
const querier = new ImageQuerier(req.query, knex('images'))
let images

try {
images = await querier.run()
} catch (error) {
// Handle validation error, such as by passing to an Express error handler:
next(error)
}

res.send({ images })
})
```

Behind-the-scenes, QueryQL takes your initial query builder (`knex('images')`),
and applies the following Knex chain when `querier.run()` is called:

```js
builder
.where('id', 'in', [2, 3])
.where('status', '=', 'open')
.orderBy('name', 'asc')
.limit(10)
.offset(0)
```

(Remember: While Knex is our default adapter and the query builder used in this
example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add
filtering, sorting, and pagination to your REST API _without_ manually touching
your query builder / ORM.

[Read the full documentation](DOCS.md) to learn how to add validation, customize
the queries, and more.

## Development

### Prerequisites

The only prerequisite is a compatible version of Node.js (see `engines.node` in
[`package.json`](package.json)).

### Dependencies

Install dependencies with npm:

```bash
npm install
```

### Tests

[Jest](https://jestjs.io/) is our testing framework of choice. We strive for
100% code coverage.

To run the tests:

```bash
npm test
```

During development, it's recommended to run the tests automatically on file
change:

```bash
npm test -- --watch [--notify]
```

### Code Style & Linting

[Prettier](https://prettier.io/) is setup to enforce a consistent code style.
It's highly recommended to
[add an integration to your editor](https://prettier.io/docs/en/editors.html)
that automatically formats on save.

[ESLint](https://eslint.org/) is setup with the
["recommended" rules](https://eslint.org/docs/latest/rules/) to enforce a level
of code quality. It's also highly recommended to
[add an integration to your editor](https://eslint.org/docs/latest/use/integrations#editors)
that automatically formats on save.

To run via the command line:

```bash
npm run lint
```

## Releasing

When the `development` branch is ready for release,
[Release It!](https://github.com/release-it/release-it) is used to orchestrate
the release process:

```bash
npm run release
```

Once the release process is complete, merge the `development` branch into the
`main` branch, which should always reflect the latest release.