Auto-generated, RESTful, CRUDdy route handlers
Lead Maintainer - Matt Boutet
npm install @hapipal/tandy
Note
This plugin is intended to work with hapi v19+ and its Objection ORM plugin, schwifty.
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:
POST
is used forcreate
,add
(create a record then add it to a relation), and forupdate
.PATCH
may also be used forupdate
.PUT
is used foradd
in order to add an existing record to a relation.GET
is used forfind
,findOne
, andpopulate
(get related records or check an association).DELETE
is used fordestroy
andremove
(remove a record from a relation).
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
↦find
Returns an array of users with an
HTTP 200 OK
response. -
GET /users/count
↦find
with/count
Returns the integer number of users matched with an
HTTP 200 OK
response. -
GET /users/{id}
↦findById
Returns user
id
with anHTTP 200 OK
response. Responds with anHTTP 404 Not Found
response if the user is not found. -
GET /users/{id}/comments
↦findById
Returns an array of comments associated with user
id
. ReturnsHTTP 200 OK
if that user is found. Returns anHTTP 404 Not Found
response if that user is not found. -
GET /users/{id}/comments/count
↦populate
with/count
Returns the integer number of comments associated with user
id
. ReturnsHTTP 200 OK
if that user is found. Returns anHTTP 404 Not Found
response if that user is not found. -
GET /users/{id}/comments/{childId}
↦populate
Returns
HTTP 204 No Content
if commentchildId
is associated with userid
. Returns anHTTP 404 Not Found
response if that user is not found or that comment is not associated with the user. -
POST /users
↦create
Creates a new user using the request payload and returns it with an
HTTP 201 Created
response. -
POST /users/{id}/comments
↦add
Creates 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 Found
response. -
PUT /users/{id}/comments/{childId}
↦add
Associates comment
childId
with userid
. Returns anHTTP 204 No Content
response on success. If the user or comment are not found, returns anHTTP 404 Not Found
response. -
DELETE /users/{id}
↦destroy
Destroys user
id
. Returns anHTTP 204 No Content
response on success. If the user doesn't exist, returns anHTTP 404 Not Found
response. -
DELETE /users/{id}/comment/{childId}
↦remove
Removes association between user
id
and commentchildId
. Returns anHTTP 204 No Content
response on success. If the user or comment doesn't exist, returns anHTTP 404 Not Found
response. -
PATCH /users/{id}
orPOST /user/{id}
↦update
Updates user
id
using the request payload (which will typically only contain the attributes to update) and responds with the updated user. Returns anHTTP 200 OK
response on success. If the user doesn't exist, returns anHTTP 404 Not Found
response.
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.
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
true
for the following options in the section to take effect. The acting user is defined by hapi authentication credentials and theuserIdProperty
option. -
userIdProperty
(string, defaults'id'
). Applies tofindOne
,find
,create
,update
,destroy
,add
,remove
, andpopulate
.When
actAsUser
istrue
this option takes effect. It defines a path intoRequest.auth.credentials
to 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
actAsUser
istrue
this option takes effect. This option works in tandem withuserModel
. When a route path begins withuserUrlPrefix
(after any other inert prefix has been stripped via theprefix
option), the URL is transformed to begin/:userModel/:actingUserId
before 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
actAsUser
istrue
this option takes effect. This option works in tandem withuserUrlPrefix
. When a route path begins withuserUrlPrefix
(after any other inert prefix has been stripped via theprefix
option), the URL is transformed to begin/:userModel/:actingUserId
before matching for a Tandy; it essentially sets the primary record to the acting user. E.g., by default whenactAsUser
is enabled, route pathPUT /user/following/10
would internally be considered asPUT /users/17/following/10
, which corresponds to theadd
Tandy applied to the authenticated user.
-
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/3
has the modeluser
. -
associationAttr
(string). Applies toadd
,remove
, andpopulate
Name of the association's Objection attribute. If not provided as an option, it is deduced from the route path.
Ex:
/user/1/files/3
has the association attributefiles
(i.e., the Objection modeluser
has an attribute,files
containing records in a one-to-many relationship). -
limit
(positive integer). Applies tofind
andpopulate
.Set default limit of records returned in a list. If not provided, this defaults to 30.
-
skip
(positive integer). Applies tofind
andpopulate
.Sets default number of records to skip in a list (overridden by
skip
query parameter). Defaults to 0. -
sort
(string). Applies tofind
andpopulate
.Sets default sorting criteria (i.e.
createdDate ASC
) (overridden bysort
query 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 bywhere
query parameter).
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
}
}
]);
- based on bedwetter, which offers similar functionality for Waterline ORM.