npm package: @nodebrick/nodebrick-api
Description: Nodebrick API module, providing express server
Author: Xavier Martin
Latest version: 1.4.19

# @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](../nodebrick-core/README.md#contexts) 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](../nodebrick-core/README.md#filter-operator-list) 

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 <Limit> 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:
```typescript
    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:
```json
{
  "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:
```json
{
  "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