hapi-holiday
Create REST API with hapi
Usage
$ npm install hapi-holiday --save
- Configures hapi-swagger by default
Example usage
Holiday.define(schemeName, scheme);
Define a scheme for the API routes.
schemeName
string (required)scheme
object (required)scheme.index
function(Model, request, done) {} (required)scheme.show
function(Model, request, done) {} (required)scheme.save
function(Model, request, done) {} (required)scheme.update
function(Model, request, done) {} (required)scheme.destroy
function(Model, request, done) {} (required)
sequelize
Example scheme usingHoliday.define('sequelize', { // GET all records index: (Model, request, done) => { Model.findAll({ offset: request.query.offset, limit: request.query.limit, }) .then((records) => { done(null, records); }) .catch((err) => { done(err, null); }); }, // GET one record show: (Model, request, done) => { Model.findById(request.params.id) .then((records) => { done(null, records); }) .catch((err) => { done(err, null); }); }, // POST a new record save: (Model, request, done) => { Model.create(request.payload).then((result) => { done(null, result); }) .catch((err) => { done(err, null); }); }, // PUT an updated record update: (Model, request, done) => { Model.update(request.payload, { where: { id: request.params.id, }, }) .then((result) => { done(null, result); }) .catch((err) => { done(err, null); }); }, // DELETE a record destroy: (Model, request, done) => { Model.destroy({ where: { id: request.params.id, }, }) .then((affected) => { done(null, affected); }) .catch((err) => { done(err, null); }); },});
Holiday.configure(config);
Optional. Overrides default configurations for hapi routes.
// Set default hapi route configs(optional)Holiday.configure({ tags: ['api'], auth: ['jwt'], ...etc.});
Create routes
new Holiday(schemeName, routeName, Model);
Creates a new instance of routes.
schemeName
string (required) - name of scheme definedrouteName
string (required) - name of routes (i.e. /routeName/{id})Model
Any (required) - Any kind of model to use
posts
model
An example for const PostApi = new Holiday('sequelize', 'posts', Models.Posts);
Validation
Api.validate.index(validationObj)
Api.validate.show(validationObj)
Api.validate.save(validationObj)
Api.validate.update(validationObj)
Api.validate.destroy(validationObj)
Set custom validations for specific route type.
validationObj
Object (required)
method | validates on |
---|---|
Api.validate.index() |
request.query |
Api.validate.show() |
request.query |
Api.validate.save() |
request.payload |
Api.validate.update() |
request.payload |
Api.validate.destroy() |
request.query |
// Example validation to use on 'save'PostApi.validate.save({title: Joi.string().required(),content: Joi.string().required(),});// Example validation to use on 'update'PostApi.validate.update({title: Joi.string(),content: Joi.string(),});
See hapi's validation tutorial for more information.
Mount routes on hapi
Api.all();
Get all routes
Api.index(config, schemeOverride, callback);
Get route for index
config
object (optional)schemeOverride
function (optional) - overrides scheme- function(Model, request, done)
callback
function (optional)- function(err, result, reply)
- err - error from model
- result - result from Model
- reply - reply object of hapi
- function(err, result, reply)
Api.show(config, schemeOverride, callback);
Get route for show
config
object (optional)schemeOverride
function (optional) - overrides scheme- function(Model, request, done)
callback
function (optional)- function(err, result, reply)
- err - error from model
- result - result from Model
- reply - reply object of hapi
- function(err, result, reply)
Api.save(config, schemeOverride, callback);
Get route for save
config
object (optional)schemeOverride
function (optional) - overrides scheme- function(Model, request, done)
callback
function (optional)- function(err, result, reply)
- err - error from model
- result - result from Model
- reply - reply object of hapi
- function(err, result, reply)
Api.update(config, schemeOverride, callback);
Get route for update
config
object (optional)schemeOverride
function (optional) - overrides scheme- function(Model, request, done)
callback
function (optional)- function(err, result, reply)
- err - error from model
- result - result from Model
- reply - reply object of hapi
- function(err, result, reply)
Api.destroy(config, schemeOverride, callback);
Get route for destroy
config
object (optional)schemeOverride
function (optional) - overrides scheme- function(Model, request, done)
callback
function (optional)- function(err, result, reply)
- err - error from model
- result - result from Model
- reply - reply object of hapi
- function(err, result, reply)
// mount routesserver.route(PostApi.all()); // same as...server.route([ PostApi.index(), PostApi.show(), PostApi.save(), PostApi.update(), PostApi.destroy(),]);
Example above creates:
GET /posts
GET /posts/{id}
POST /posts
PUT /posts/{id}
DELETE /posts/{id}
Customizing specific routes
server.route([ PostApi.index({ /* can override any configuration here */ tags: ['api', 'get'], auth: ['jwt'], // ... }, (Model, request, done) => { /* can override scheme for this route only */ // Model = Model given as third param of 'new Holiday()' // request = request object of hapi // done = callback function to execute when done }, (err, result, reply) => { /* can customize replies and status codes here */ // err = error of model // result = result of model // reply = reply object of hapi }), PostApi.show({ /* can override any configuration here */ tags: ['api', 'post'], auth: ['jwt'], // ... }, (Model, request, done) => { /* can override scheme for this route only */ // Model = Model given as third param of 'new Holiday()' // request = request object of hapi // done = callback function to execute when done }, (err, result, reply) => { /* can customize replies and status codes here */ // err = error of model // result = result of model // reply = reply object of hapi }), // ... and so on]);
Adding a route for 1:1 or 1:n models
Api.has(resourceName, scheme);
Creates a new route under GET /modelName/{id}/resourceName
Cannot use index
, show
, save
, update
, destroy
for resourceName
resourceName
string (required) - name for the associationscheme
function (required)- function(Model, request, done) {}
- Model - error from model
- request - request object of hapi
- done - a function to execute when done.
- done(err, result)
- err - Error message or null
- result - result of model
- done(err, result)
- function(Model, request, done) {}
// This adds GET /posts/{id}/authorPostApi.has('author', (Models, request, done) => { Model.find({ where: {id: request.params.id}, include: ['Author'] }) .then((records) => { done(null, records); }) .catch((err) => { done(err, null); });});
Api.validate.resource[resourceName](validationObj);
Set validations for association routes.
Validation set with this method validates on request.query
// NOTE: always validate after executing Api.has()PostApi.validate.resource.author({ name: Joi.string(), // ...});
Api.resource[resourceName](config, schemeOverride, callback)
Get route for association
config
object (optional)schemeOverride
function (optional) - overrides scheme- function(Model, request, done)
callback
function (optional)- function(err, result, reply)
- err - error from model
- result - result from Model
- reply - reply object of hapi
- function(err, result, reply)
// mount association routeserver.route(PostApi.resource.author()); // all routes including resource gets mounted by using Api.all()server.route(PostApi.all());
More examples...
var Hapi = require('hapi');var Holiday = require('hapi-holiday');var Joi = require('joi'); var server = new Hapi.Server();server.connection({ port: 3000 }); Holiday.define('testScheme', { index: function(Model, request, done) { done(null, {test: 'index'}); }, show: function(Model, request, done) { done(null, {test: 'show', id: request.params.id}); }, save: function(Model, request, done) { done(null, {test: 'save'}); }, update: function (Model, request, done) { done(null, {test: 'update', id: request.params.id}); }, destroy: function(Model, request, done) { done(null, {test: 'destroy', id: request.params.id}); },}); var Api = new Holiday('testScheme', 'test', {a: 'model'}); Api.has('photo', function(Model, request, done) { done(null, { a: 'photo', name: request.query.name, someId: request.query.someId, });}); Api.validate.resource.photo({ name: Joi.string(), someId: Joi.number(),}); server.route(Api.all()); server.start(function () { console.log('Server running at:', server.info.uri);}); // GET http://localhost:3000/test// will return...// {// "test": "index"// }// with a status code 200 OK // GET http://localhost:3000/test/11// will return...// {// "test": "show",// "id": 11// }// with a status code 200 OK // POST http://localhost:3000/test// will return...// {// "test": "save"// }// with a status code 201 Created // PUT http://localhost:3000/test/22// will return...// {// "test": "update",// "id": 22// }// with a status code 200 OK // DELETE http://localhost:3000/test/33// will return nothing with a status code 204 No Content // GET http://localhost:3000/test/1/photo?name=nano&someId=100// will return...// {// "a": "photo",// "name": "nano",// "someId": 100// }// with a status code 200 OK // GET http://localhost:3000/test/1/photo?name=nano&someId=hello// will return...// {// "statusCode": 400,// "error": "Bad Request",// "message": "child \"someId\" fails because [\"someId\" must be a number]",// "validation": {// "source": "query",// "keys": [// "someId"// ]// }// }// with a status code 400 Bad Request
Dependencies
dependencies
devDependencies
License
MIT