hapi-sequelize-crud2
Automatically generate a RESTful API for your models and associations, with simple route configuration and behavior extensibility.
This plugin depends on hapi-sequelize
, and builds on the work of hapi-sequelize-crud
.
npm install -S hapi-sequelize-crud2
##Configure
await server.register({
register: require('hapi-sequelize'),
options: { ... }
});
const db = server.plugins['hapi-sequelize'].db;
const models = db.sequelize.models;
associations(models);
await server.register({
register: require('hapi-sequelize-crud2'),
options: {
prefix: '',
scopePrefix: 's',
snakeCase: false,
controllers: 'controllers/**/*.js',
private: []
}
});
Please note that you should register hapi-sequelize-crud2
after defining your
associations.
##What do I get
Let's say you have associations like this:
Team.belongsToMany(Role, { through: 'teamRoles' });
Team.hasOne(Player, { as: 'captain' });
You get these CRUD routes:
Method | Route | Name |
---|
GET | /teams | index1 2 3 |
GET | /teams/{id} | get3 |
POST | /teams | create |
PUT | /teams/{id} | update |
DELETE | /teams/{id} | destroy |
GET | /teams/s/{scope} | scope1 2 3 |
GET | /teams/count | count1 |
And these one-to-one association routes:
Method | Route | Name | Description |
---|
GET | /teams/{id}/captain | index3 | Retrieve the related model |
POST | /teams/{id}/captain | create | Create a new related model and sets the association |
PUT | /teams/{id}/captain/{aid} | update | Sets the association with an existing related model |
DELETE | /teams/{id}/captain | destroy | Unsets the association |
And these one-to-many association routes:
Method | Route | Name | Description |
---|
GET | /teams/{id}/roles | index1 2 3 | Retrieve the related models |
POST | /teams/{id}/roles | create | Create a new related model and adds it to the associations |
PUT | /teams/{id}/roles/{aid} | update | Sets the association with an existing related model |
PUT | /teams/{id}/roles | updateMany | Sets the association with a many related models, as provided by id[] querystring parameter |
DELETE | /teams/{id}/roles/{aid} | destroy | Unsets the association |
DELETE | /teams/{id}/roles | destroyMany | Unsets all associations, optionally limited to those given by id[] querystring parameter |
GET | /teams/{id}/roles/count | count1 | Counts the number of associated models |
1 Accepts a query string parameter object filter
to limit results by given criteria, e.g. ?filter[status]=active
2 Accepts query string parameters limit
and offset
to control paginated results
3 Accepts a querystring parameter include
to include a related model with the returned parent model
##Custom Route Configuration
Automatic route handling is convenient for getting a basic API in place during development. But
in a production application, authentication, ACL and caching concerns need to be addressed.
Taking advantage of Hapi's convention over configuration approach to route set-up, you can easy
extend and override the plugin's default route options and handler.
Simply create a file named modelName.js (or model_name.js if you prefer) in your controllers path
defined in the plugin options, and your options will be mixed in during route registration. A
controller should export a function that accepts two arguments, a Hapi server instance and the model
object, and returns an object mapping route names to Hapi route configuration object partials or
false
to disable a route.
Include a default configuration to apply to all routes in a controller by setting the *
key.
Apply only to all association routes by setting associations.*
. To set a default controller,
include a _default.js
file in your controllers file path.
For example, a read-only endpoint with limited scope access may look like:
const Hoek = require('hoek');
const Joi = require('joi');
modules.export = function(server, Team) {
const plural = Team.options.name.plural;
return {
'*': {
cache: {
expiresIn: 30 * 1000,
private: 'private'
}
},
scope: {
config: {
validation: {
params: {
scope: Joi.string().valid('scope1', 'scope2')
}
}
}
},
count: {
path: `${plural}/total`,
handler: function(request, reply) {
...
const total = ...;
reply({total: total});
}
},
create: false,
update: false,
destroy: false,
associations: {
captain: {
create: false,
update: false,
destroy: false
},
roles: false
}
};
});
Provide Already Retrieved Model
Have you already queried for and retrieved the model instance (or parent instance for association
routes) earlier in your pre-handler cycle? You can provide this to the plugin by assigning the
request.pre.model
key to your request object and it will not execute the find query.
Dynamic Scope Limiting
Need to assign a scope based on ACL or other pre-handler results? Assign the request.pre.scope
key
to your request object and it will apply the supplied pre-defined model scopes to the find queries.