@nodebrick/nodebrick-api
TypeScript icon, indicating that this package has built-in type declarations

1.4.19 • Public • Published

@nodebrick/nodebrick-api

__

Description

  • api port

Install

$ npm install --save @nodebrick/nodebrick-api

Usage

Authorization

Options

The nodebrick-api has a middleware that will parse the options query parameter. The options query parameter can have none or all the following objects
{fieds:{}, filters:{}, sort{}}
How each string is defined for fields, filters and sort is covered further down.

The parsed options (options of type nodebrick-core/src/models/IResourceOptions) will be available in the controller using the @Options decorator. It will also be available in the application context under IResourceOptionContext, i.e applicationContext.get(IResourceOptionsContext) Please read the nodebrick-core context documentation for more information on contexts.

All options use the following way of selecting objects
Use a comma-separated list to select multiple fields.
Use a/b to select a property b that is nested within object a; use a/b/c to select a property c nested within b nested within a.

Use a sub-selector to request a set of specific sub-fields of arrays or objects by placing expressions in parentheses ( ). For example: {fields:{items(id,author/email)}} returns only the item ID and author's email for each element in the items array. You can also specify a single sub-field, where {fields:{items(id)}} is equivalent to {fields:{items/id}}.

Sorting

Use a comma-separated list to select multiple fields.
For example:

  • {sort:{email:DESC)}} will sort on email field, DESC
  • {sort:{contact/email:DESC)}} will sort on the contact.email field, DESC

IOptionSort, parsed version of the sort option will be available in the application context under IOptionSortContext, i.e applicationContext.get(IOptionSortContext)
In the controller you will also be able to access the filters via the options.sort, options being the object decorated with @Options in the method parameters.

Example ?options={sort:{name:DESC}} The following fields object will be available

    {
      "createdAt": "2019-01-24T21:38:55.011Z",
      "updatedAt": "2019-01-24T21:38:55.011Z",
      "deletedAt": null,
      "uuid": "b989ad79-c0ab-47d8-ac1a-745c8ae52f61",
      "name": "wellington",
      "population": 418500,
      "date": "2019-01-24T21:38:55.011Z"
    },
    {
      "createdAt": "2019-02-01T00:55:19.285Z",
      "updatedAt": "2019-02-01T00:55:19.285Z",
      "deletedAt": null,
      "uuid": "eda0172b-a1b4-40b2-a3bd-d3ca684317aa",
      "name": "tauranga",
      "population": 141600,
      "date": "2019-02-01T00:55:19.285Z"
    },
    {
      "createdAt": "2019-02-01T00:55:19.051Z",
      "updatedAt": "2019-02-01T00:55:19.051Z",
      "deletedAt": null,
      "uuid": "8708664d-211b-48c6-bae4-016ddaa96217",
      "name": "tauranga",
      "population": 141600,
      "date": "2019-02-01T00:55:19.051Z"
    },
    {
      "createdAt": "2019-02-01T00:55:18.803Z",
      "updatedAt": "2019-02-01T00:55:18.803Z",
      "deletedAt": null,
      "uuid": "e7d1af07-3016-4903-bc19-6ef406a58428",
      "name": "tauranga",
      "population": 141600,
      "date": "2019-02-01T00:55:18.803Z"
    },
    {
      "createdAt": "2019-02-01T00:55:17.679Z",
      "updatedAt": "2019-02-01T00:55:17.679Z",
      "deletedAt": null,
      "uuid": "11938bdd-1687-4ea1-a763-7a4333e90117",
      "name": "tauranga",
      "population": 141600,
      "date": "2019-02-01T00:55:17.679Z"
    }
    ...

Fields selection

Use a comma-separated list to select multiple fields.

For example:

  • {fields:{items}} returns only the item object/array/property.
  • {fields:{items(id,author/email)}} returns only the item ID and author's email for each element in the items array.

IOptionFields, parsed version of the fields option will be available in the application context under IOptionFieldsContext, i.e applicationContext.get(IOptionFieldsContext)

Example ?options={fields:{author,library(name/common,address(city,country/code)),price}} The following fields object will be available

{
    author: true,
    library: {
        name: {
            common: true
        },
        address: {
            city: true,
            country: {
                code: true
            }
        }
    },
    price: true
}

This object is used by the interceptor to trim down the resource sent back.
If a specified field doesn't exists on the resource it will error.

Filters selection

Use a comma-separated list to select multiple filters.
A filter is structured like property:operator_value for one value or property:operator_value1_value2... if multiple values are requires by the operator

You can see the list of all available operator on the nodebrick-core documentation

For example:

  • {filters:{email:$like_%xavier.martin%)}} will ask to return all object having email like %xavier.martin%
  • {filters:{contactemail:$like_%xavier.martin%)}} will ask to return all object having contact.email like %xavier.martin%

OptionFilters, parsed version of the filter option will be available in the application context under OptionFiltersContext, i.e applicationContext.get(OptionFiltersContext)
In the controller you will also be able to access the filters via the options.filters, options being the object decorated with @Options in the method parameters.
The filters object has keys as the properties you filtered on. The value looking like this:

property: string,
value: [string]|[string,string],
operator: FilterOperatorsEnum,
operatorSQL: [string]|[string, string]

Example ?options={filters:{author:$like_stephen king,book:$nilike_it,date:$between_1995-01-01_2018-12-12}}

The following filters object will be available:

{
      author: {
        property: "author",
        value: [
          "stephen king"
        ],
        operator: "$like",
        operatorSQL: [
          "LIKE"
        ]
      },
      book: {
        property: "book",
        value: [
          "it"
        ],
        operator: "$nilike",
        operatorSQL: [
          "NOT ILIKE"
        ]
      },
      date: {
        property: "date",
        value: [
          "1995-01-01",
          "2018-12-12"
        ],
        operator: "$between",
        operatorSQL: [
          "BETWEEN",
          "AND"
        ]
      }
    }

Use this object to alter your query.

Count & Paginate

We have implemented two types of paginations, seek and offset.

Offset pagination requires the record you want to start from and a limit (number of records to return).
This is VERY inefficient. It requires the database to also work with on all the previous records.
This is somehow the default almost everywhere.

Seek (extension of keyset pagination, have a look) pagination where you give the ID to get result after or before. This also use the limit (number of item to return). This is efficient as the database will jump exactly to this record and the next number and work on those.

How to Implement it in our backend

So the nodebrick-api has written those contexts, how can they be leveraged?
An example is the nodebrick-database as show here:

    public async getManyWithQueryBuilder(): Promise<IModel[]> 
    {
        //  create the query builder
        const query: SelectQueryBuilder<IModel> = this.manager.createQueryBuilder(IModel, "mod_a");
        //  ask the service the count value
        //  this is executed only if the client requested a count, see later
        await this._dbService.filter(query);
        await this._dbService.sort(query);
        await this._dbService.paginate(query);
        await this._dbService.count(query);
        // or you can do
        await this._dbService.applyOptions(query);
        return query.getMany();
    }

and that's it.

The count method will count records, if requested by the client The paginate method will paginate the result if requested by the client

How to request count or pagination

Count

Add the following query parameters:

  • count: boolean
    returns a count field (integer) in the response object, sibling to the data property

A count property will be added to the response with the following structure

{
  "do_count": <boolean>,
  "count": <integer>
}

Example

Request:
/resource?count=true

Response:

{
  "data": {},
  "count": {
    "do_count": true,
    "count": 40
  }
}

Offset

Add the following query parameters:

  • start: integer
    returns start at the record counts
  • limit: integer
    return this number of records

Example

Request:
/resource?limit=5&start=5

Response:

{
  "data": {},
  "pagination": {
    "type": "offset",
    "limit": 5,
    "start": 5,
    "prev_url": "/resource?limit=5&start=0",
    "self_url": "/resource?limit=5&start=5",
    "next_url": "/resource?limit=5&start=10"  
  }
}
Seek

Add the following query parameters:

  • limit: integer.
    Return this number of records
  • before: UUID
    Return the records before this UUID OR
  • after: UUID
    Return the records after this UUID

Example

Request:
/resource?limit=5&before=c8dae5da-0b64-4b55-ab56-95f59b9eb8b2

Response:

{
  "data": {},
  "pagination": {
    "type": "seek",
    "limit": 5,
    "after": null,
    "before": "c8dae5da-0b64-4b55-ab56-95f59b9eb8b2",
    "self": "/nodebrick-api/options?limit=5&before=c8dae5da-0b64-4b55-ab56-95f59b9eb8b2&options=%7Bfields%3A%7Bauthor,library(name%2Fcommon,address(city,country%2Fcode)),price%7D,filters%3A%7Bauthor%3A%24like_stephen%20king,book%3A%24nilike_it,date%3A%24between_1995-01-01_2018-12-12%7D%7D",
    "prev": "/nodebrick-api/options?limit=5&before=undefined&options=%7Bfields%3A%7Bauthor,library(name%2Fcommon,address(city,country%2Fcode)),price%7D,filters%3A%7Bauthor%3A%24like_stephen%20king,book%3A%24nilike_it,date%3A%24between_1995-01-01_2018-12-12%7D%7D"  
  }
}

Contexts

Decorators

Middleware

Readme

Keywords

Package Sidebar

Install

npm i @nodebrick/nodebrick-api

Homepage

nodebrick.io

Weekly Downloads

0

Version

1.4.19

License

MIT

Unpacked Size

170 kB

Total Files

86

Last publish

Collaborators

  • nolazybits