tandy v2.0.1
tandy
Auto-generated, RESTful, CRUDdy route handlers
Lead Maintainer - Matt Boutet
Note
This plugin is intended to work with hapi v19+ and its Objection ORM plugin, schwifty.
What it does
Tandy registers route handlers based upon the method and path of your route. It turns them into RESTful API endpoints that automatically interact with models defined through Schwifty. By default Tandy will infer which models to use from the request path. The route handler is based on one of eight Tandys:
POSTis used forcreate,add(create a record then add it to a relation), and forupdate.PATCHmay also be used forupdate.PUTis used foraddin order to add an existing record to a relation.GETis used forfind,findOne, andpopulate(get related records or check an association).DELETEis used fordestroyandremove(remove a record from a relation).
Tandy Patterns
Suppose users are associated with comments via an Objection relation. The user model associates comments in an relation named comments. Here are some examples as to how the plugin will deduce which of the eight Tandys to use, based upon route method and path definition.
GET /users↦findReturns an array of users with an
HTTP 200 OKresponse.GET /users/count↦findwith/countReturns the integer number of users matched with an
HTTP 200 OKresponse.GET /users/{id}↦findByIdReturns user
idwith anHTTP 200 OKresponse. Responds with anHTTP 404 Not Foundresponse if the user is not found.GET /users/{id}/comments↦findByIdReturns an array of comments associated with user
id. ReturnsHTTP 200 OKif that user is found. Returns anHTTP 404 Not Foundresponse if that user is not found.GET /users/{id}/comments/count↦populatewith/countReturns the integer number of comments associated with user
id. ReturnsHTTP 200 OKif that user is found. Returns anHTTP 404 Not Foundresponse if that user is not found.GET /users/{id}/comments/{childId}↦populateReturns
HTTP 204 No Contentif commentchildIdis associated with userid. Returns anHTTP 404 Not Foundresponse if that user is not found or that comment is not associated with the user.POST /users↦createCreates a new user using the request payload and returns it with an
HTTP 201 Createdresponse.POST /users/{id}/comments↦addCreates a new comment using the request payload and associates that comment with user
id. Returns that comment with anHTTP 201 Created response. If that user is not found, returns anHTTP 404 Not Foundresponse.PUT /users/{id}/comments/{childId}↦addAssociates comment
childIdwith userid. Returns anHTTP 204 No Contentresponse on success. If the user or comment are not found, returns anHTTP 404 Not Foundresponse.DELETE /users/{id}↦destroyDestroys user
id. Returns anHTTP 204 No Contentresponse on success. If the user doesn't exist, returns anHTTP 404 Not Foundresponse.DELETE /users/{id}/comment/{childId}↦removeRemoves association between user
idand commentchildId. Returns anHTTP 204 No Contentresponse on success. If the user or comment doesn't exist, returns anHTTP 404 Not Foundresponse.PATCH /users/{id}orPOST /user/{id}↦updateUpdates user
idusing the request payload (which will typically only contain the attributes to update) and responds with the updated user. Returns anHTTP 200 OKresponse on success. If the user doesn't exist, returns anHTTP 404 Not Foundresponse.
Options
Options can be passed to the plugin when registered or defined directly on the route handler. Those defined on the route handler override those passed to the plugin on a per-route basis.
Acting as a User
These options allow you to act on behalf of the authenticated user. Typically the user info is taken directly off the credentials object without checking the request.auth.isAuthenticated flag. This allows you to use authentication modes however you wish.
actAsUser(boolean, defaultsfalse). Applies tofindOne,find,create,update,destroy,add,remove, andpopulate.This must be set to
truefor the following options in the section to take effect. The acting user is defined by hapi authentication credentials and theuserIdPropertyoption.userIdProperty(string, defaults'id'). Applies tofindOne,find,create,update,destroy,add,remove, andpopulate.When
actAsUseristruethis option takes effect. It defines a path intoRequest.auth.credentialsto determine the acting user's id. For example, if the credentials object equals{user: {info: {id: 17}}}then'user.info.id'would grab user id17. SeeHoek.reach, which is used to convert the string to a deep property in the hapi credentials object.userUrlPrefix(string, defaults'/user'). Applies tofindOne,update,destroy,add,remove, andpopulate.When
actAsUseristruethis option takes effect. This option works in tandem withuserModel. When a route path begins withuserUrlPrefix(after any other inert prefix has been stripped via theprefixoption), the URL is transformed to begin/:userModel/:actingUserIdbefore matching for a Tandy; it essentially sets the primary record to the acting user.userModel(string, defaults'users'). Applies tofindOne,update,destroy,add,remove, andpopulate.When
actAsUseristruethis option takes effect. This option works in tandem withuserUrlPrefix. When a route path begins withuserUrlPrefix(after any other inert prefix has been stripped via theprefixoption), the URL is transformed to begin/:userModel/:actingUserIdbefore matching for a Tandy; it essentially sets the primary record to the acting user. E.g., by default whenactAsUseris enabled, route pathPUT /user/following/10would internally be considered asPUT /users/17/following/10, which corresponds to theaddTandy applied to the authenticated user.
Other Options
prefix(string). Applies tofindOne,find,create,update,destroy,add,remove, andpopulate.Allows one to specify a prefix to the route path that will be ignored when determining which Tandy to apply.
model(string). Applies tofindOne,find,create,update,destroy,add,remove, andpopulate.Name of the model's Objection identity. If not provided as an option, it is deduced from the route path.
Ex:
/user/1/files/3has the modeluser.associationAttr(string). Applies toadd,remove, andpopulateName of the association's Objection attribute. If not provided as an option, it is deduced from the route path.
Ex:
/user/1/files/3has the association attributefiles(i.e., the Objection modeluserhas an attribute,filescontaining records in a one-to-many relationship).limit(positive integer). Applies tofindandpopulate.Set default limit of records returned in a list. If not provided, this defaults to 30.
skip(positive integer). Applies tofindandpopulate.Sets default number of records to skip in a list (overridden by
skipquery parameter). Defaults to 0.sort(string). Applies tofindandpopulate.Sets default sorting criteria (i.e.
createdDate ASC) (overridden bysortquery parameter). Defaults to no sort applied.where(string). Applies tofind.Extracts only those records that fulfill a specified condition. (i.e.
createdDate = '2019-08-19')(overridden bywherequery parameter).
Usage
Here's an (over)simplified example.
// Assume `server` is a hapi server with the Tandy plugin registered.
// Models with names 'Zoo' and 'Treat' exist via Schwifty.
// Zoos and Treats are in a many-to-many correspondence with each other.
// Check-out the test/ folder for further details.
server.route([
{ // findOne
method: 'GET',
path: '/zoo/{id}',
handler: {
tandy: options
}
},
{ // find
method: 'GET',
path: '/treat',
handler: {
tandy: options
}
},
{ // destroy
method: 'DELETE',
path: '/treat/{id}',
handler: {
tandy: options
}
},
{ // create
method: 'POST',
path: '/zoo',
handler: {
tandy: options
}
},
{ // update
method: ['PATCH', 'POST'],
path: '/treat/{id}',
handler: {
tandy: options
}
},
{ // remove
method: 'DELETE',
path: '/zoo/{id}/treats/{childId}',
handler: {
tandy: options
}
},
{ // create then add
method: 'POST',
path: '/zoo/{id}/treats',
handler: {
tandy: options
}
},
{ // add
method: 'PUT',
path: '/zoo/{id}/treats/{childId}',
handler: {
tandy: options
}
},
{ // populate
method: 'GET',
path: '/zoo/{id}/treats/{childId?}',
handler: {
tandy: options
}
}
]);Extras
- based on bedwetter, which offers similar functionality for Waterline ORM.