npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@nodebrick/nodebrick-api

v1.4.19

Published

Nodebrick API module, providing express server

Downloads

3

Readme

@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