@apparts/model-api
v4.2.1
Published
Generate CRUDish API-endpoints for a model defined with the @apparts/model package
Downloads
126
Readme
#+TITLE: @apparts/model-api #+DATE: [2021-02-08 Mon] #+AUTHOR: Philipp Uhl
Generate CRUDish API-endpoints for a model defined with the [[https://github.com/apparts-js/apparts-model][@apparts/model]] package.
- Installation
#+BEGIN_SRC js npm i --save @apparts/model-api #+END_SRC
- Usage
To generate CRUD-like API-endpoints for a model, use the =addCrud= function.
- =addCrud({ prefix, app, model, routes })=
- =prefix : string= :: The prefix for the URI, can contain parameters (see next section).
- =app : App= :: The express app
- =model : function= :: A function that returns an array in the form of =[OneModel, ManyModel, NoneModel]= (as does the =makeModel= function from [[https://github.com/apparts-js/apparts-model][@apparts/model]] package).
- =routes : object= :: An object that contains options for the routes
to be generated. If one of the keys is not present in the object,
that route will not be generated. Possible keys are:
- =get= :: The get all route
- =getByIds= :: The get by ids route
- =post= :: The create item route
- =put= :: The update item route
- =patch= :: The patch item route
- =delete= :: The delete items route The values for each of these keys are objects, that can contain:
- =hasAccess : (request) -> Promise= :: A functions that defines access rights for the individual endpoint. It receives the same parameters as a request handler from [[https://github.com/apparts-js/apparts-types][@apparts/types]] receives. If the function throws an HttpError (from [[https://github.com/apparts-js/apparts-prep][@apparts/prep]]), access will be rejected. If another error is thrown, a 500 error will be produced. Otherwise access will be granted.
- =title : string= :: A custom title for the documentation
- =description : string= :: A custom description for the documentation
- =idField?: string= :: (optional, default value is =id=) When using a field for identifying, named different than =id=, you must specify the fields name using this parameter. This also changes the routes to use the =idField='s value instead of =id= and =(idField + 's')= for the pluralizations of =id= (e.g. =GET /v/1/user/:customIds= for =idField= of =customId=).
#+BEGIN_SRC js const { addCrud, anybody } = require("@apparts/model-api");
const addRoutes = (app) => { // ...add your routes
addCrud("/v/1/user", app, useUser, { get: anybody, getByIds: anybody, post: anybody, put: anybody, patch: anybody, delete: anybody, }); }; #+END_SRC
Adds these routes:
- =GET /v1/user= :: The get all route (=get=)
- =GET /v/1/user/:ids= :: The get by ids route (=getByIds=)
- =POST /v/1/user= :: The create item route (=post=)
- =PUT /v/1/user/:id= :: The update item route (=put=)
- =PATCH /v/1/user/:id= :: The patch item route (=patch=)
- =DELETE /v/1/user/:ids= :: The delete items route (=delete=)
All these routes have access control defined by you through the =access= parameter when defining the routes.
** Custom route prefixes for more REST-style access
#+BEGIN_SRC js const { addCrud, anybody } = require("@apparts/model");
// create comment model with this type:
const types = {
id: {
type: "id",
public: true,
auto: true,
key: true
},
userid: { type: "id", public: true },
createdOn: {
type: "time",
default: (c) => c.optionalVal || Date.now()
},
comment: { type: "string", public: true },
};
// add routes addCrud("/v/1/user/:userid/comment", app, useComments, { get: { hasAccess: anybody }, getByIds: { hasAccess: anybody }, post: { hasAccess: anybody }, put: { hasAccess: anybody }, patch: { hasAccess: anybody }, delete: { hasAccess: anybody }, }); #+END_SRC
Adds these routes:
- =GET /v/1/user/:userid/comment=
- =GET /v/1/user/:userid/comment/:ids=
- =POST /v/1/user/:userid/comment=
- =PUT /v/1/user/:userid/comment/:id=
- =PATCH /v/1/user/:userid/comment/:id=
- =DELETE /v/1/user/:userid/comment/:ids=
Note, that the parameter =userid= from the route is /automatically/ /matched/ against the =userid= field from the model.
** Access management
In the previous examples, all routes where created accessible for anybody. That is most likely not what you want. Instead, you can define a function for each crud operation that decides if access should be granted. This function receives all parameters of the API-call and uses them to determine if access should be granted.
To learn more about the access function and how to use it, visit [[https://github.com/apparts-js/apparts-prep#access-control][@apparts/prep - Access Control]].
** Special parameters in the model
When defining the type of your model, you can use all the parameters as defined by [[https://github.com/phuhl/apparts-model][@apparts/model]] (e.g. =public=, =mapped=, =optional=, =derived=, =auto=). The generated API endpoints respect these values:
- Only types with =public: true= are shown on GET and can be set with POST and PUT
- Types with =mapped: true= are shown to the outside with their mapped names
- Types with =optional: true= are optional and don't have to be set
- Types with =auto= or a =derived= function can not be set on PUT or POST
- The =derived= function can be used to fetch sub object as the =derived= function is called asynchronously.
Additionally, @apparts/model-api respects the value =readOnly=:
- Types with =readOnly: true= can only be read. It's value have to be created with a =default= function. This can be useful, e.g. for a created date, that should be readable (i.e. public) but not be modifiable.