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 | |
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 | |
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.
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;
const readConfig = {
cache: {
expiresIn: 30 * 1000,
private: 'private'
}
};
return {
index: readConfig,
get: readConfig,
scope: Hoek.applyToDefaults(readConfig, {
config: {
validation: {
params: {
scope: Joi.string().valid('scope1', 'scope2')
}
}
}
}),
count: Hoek.applyToDefaults(readConfig, {
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
}
};
});