hapi-forest
Advanced tools
Comparing version 0.1.2 to 0.2.0
@@ -154,2 +154,4 @@ 'use strict'; | ||
server.expose('stubJoi', stubJoi); | ||
next(); | ||
@@ -159,3 +161,3 @@ }; | ||
module.exports.attributes = { | ||
pkg: require('./package.json') | ||
pkg: require('./package.json'), | ||
}; |
'use strict'; | ||
const boom = require('boom'); | ||
const hu = require('../lib/handler-utils'); | ||
@@ -10,8 +10,8 @@ module.exports = (route, options) => { | ||
Model.create(req.payload, (err, mod) => { | ||
Model.create(req.payload, (err, item) => { | ||
if (err) return reply(boom.badImplementation(err)); | ||
return reply(mod); | ||
if (err) return hu.handleError(err, reply); | ||
return reply(item).code(201); | ||
}); | ||
}; | ||
}; |
'use strict'; | ||
const boom = require('boom'); | ||
const joi = require('joi'); | ||
@@ -18,3 +17,3 @@ const hu = require('../lib/handler-utils'); | ||
if (err) return reply(boom.badImplementation(err)); | ||
if (err) return hu.handleError(err, reply); | ||
return reply(mod); | ||
@@ -21,0 +20,0 @@ }); |
'use strict'; | ||
const joi = require('joi'); | ||
const boom = require('boom'); | ||
@@ -8,3 +9,3 @@ exports.getId = (opts, req) => { | ||
return params[opts.idKey] || req.params.id || req.paramsArray[0]; | ||
} | ||
}; | ||
@@ -14,6 +15,28 @@ exports.getIdQuery = (opts, req) => { | ||
return { [opts.idKey]: id }; | ||
} | ||
}; | ||
const mongo3Match = /collection: .*\..+ index: (.+)_\d+ dup/; | ||
const mongo2Match = /E11000 duplicate key error index: .+\..+\.\$(.+)_\d+ {2}dup/; | ||
exports.handleError = (err, reply) => { | ||
// duplicate key | ||
if (err.code === 11000) { | ||
let fieldName = 'field'; | ||
// try mongodb 3 error string first | ||
const m3 = err.message.match(mongo3Match); | ||
if (m3 !== null) fieldName = m3[1]; | ||
else { | ||
// fallback to mongodb 2 error string | ||
const m2 = err.message.match(mongo2Match); | ||
if (m2 !== null) fieldName = m2[1]; | ||
} | ||
return reply(boom.conflict(`Entry with that ${fieldName} already exists`, { | ||
fieldName, | ||
})); | ||
} | ||
return reply(boom.badImplementation(err)); | ||
}; | ||
exports.schemas = { | ||
idKey: joi.string().default('_id').example('nickname'), | ||
}; |
@@ -30,10 +30,14 @@ 'use strict'; | ||
const fromProperty = (schema) => { | ||
const { instance } = schema; | ||
const fromProperty = (mSchema) => { | ||
const { instance } = mSchema; | ||
let joiSchema; | ||
if (transforms[instance] !== undefined) { | ||
return transforms[instance](schema).label(schema.path); | ||
joiSchema = transforms[instance](mSchema).label(mSchema.path); | ||
} else { | ||
// TODO: debug log | ||
return transforms.any(schema); | ||
joiSchema = transforms.any(mSchema); | ||
} | ||
if (mSchema.isRequired === true) joiSchema = joiSchema.required(); | ||
return joiSchema; | ||
} | ||
@@ -53,3 +57,3 @@ | ||
return joi.object().keys(newSchema).label(modelName); | ||
return joi.object().keys(newSchema).label(modelName).required(); | ||
}; |
{ | ||
"name": "hapi-forest", | ||
"version": "0.1.2", | ||
"version": "0.2.0", | ||
"description": "A hapi plugin to generate routes based on mongoose models", | ||
@@ -41,5 +41,6 @@ "main": "forest.js", | ||
"devDependencies": { | ||
"ava": "^0.16.0", | ||
"ava": "^0.17.0", | ||
"blipp": "^2.3.0", | ||
"eslint": "^3.5.0", | ||
"eslint-plugin-ava": "^4.0.0", | ||
"hapi": "^15.0.3", | ||
@@ -50,3 +51,3 @@ "hapi-swagger": "^7.2.0", | ||
"mongoose": "^4.6.0", | ||
"nyc": "^8.1.0", | ||
"nyc": "^9.0.1", | ||
"pre-commit": "^1.1.3", | ||
@@ -53,0 +54,0 @@ "vision": "^4.1.0" |
@@ -19,4 +19,10 @@ hapi-forest | ||
## Plugin usage | ||
## Quickstart | ||
1. Install it | ||
```shell | ||
npm i --save hapi-forest # or yarn add hapi-forest if you prefer | ||
``` | ||
2. Register the plugin. | ||
```JavaScript | ||
@@ -27,2 +33,3 @@ // register hapi-forest | ||
options: { | ||
// add your models here for auto route generation | ||
bootstrap: [ require('./models/user-model') ] | ||
@@ -33,2 +40,4 @@ } | ||
3. Test your dynamically generated REST endpoints. [hapi-swagger](https://github.com/glennjones/hapi-swagger) works nicely with hapi-forest. | ||
Take a look at the `example` directory for a full example. | ||
@@ -45,8 +54,10 @@ | ||
Handlers are dynamically generated based on your route definition. | ||
You can use the `forest` handler and define your own routes, instead of auto-generating | ||
them. This is useful if you need more control over your endpoints or want custom validation. | ||
`GET`, `POST`, `PATCH` & `PUT` routes will generate an according REST handler. | ||
You can also overwrite the handlers by setting the `type` option for every handler. | ||
The forest handler behaves differently based on your route definition. | ||
`GET`, `POST`, `PATCH` & `PUT` are supported. | ||
The `model` option is required for every handler. | ||
You can also overwrite the behaviour by setting the `type` option. | ||
The `model` option is always required. | ||
@@ -53,0 +64,0 @@ ### `getOne` |
@@ -1,9 +0,6 @@ | ||
'use strict'; | ||
const test = require('ava'); | ||
const hapi = require('hapi'); | ||
const Hapi = require('hapi'); | ||
test.cb('register without errors (no opts)', (t) => { | ||
const server = new Hapi.Server(); | ||
const server = new hapi.Server(); | ||
server.register({ | ||
@@ -19,3 +16,3 @@ register: require('../forest') | ||
test.cb('registerand bootstrap', (t) => { | ||
const server = new Hapi.Server(); | ||
const server = new hapi.Server(); | ||
server.connection({ host: 'localhost' }); // will never be used | ||
@@ -22,0 +19,0 @@ server.register({ |
@@ -1,14 +0,21 @@ | ||
'use strict'; | ||
const test = require('ava'); | ||
const hapi = require('hapi'); | ||
const Hapi = require('hapi'); | ||
const CatModel = require('./fixtures/test-cat-model'); | ||
const server = new Hapi.Server(); | ||
server.register(require('../forest')); | ||
server.connection({ host: 'localhost' }); // will never be used | ||
test.beforeEach.cb(t => { | ||
const server = new hapi.Server(); | ||
server.connection({ port: 9999 }); // never started | ||
server.register({ | ||
register: require('../forest'), | ||
}, e => { | ||
t.true(e === undefined, 'no error'); | ||
t.context.server = server; | ||
t.end(); | ||
}); | ||
}); | ||
const CatModel = require('../example/models/cat-model') | ||
test('throw for missing handler', (t) => { | ||
test('throw for missing handler', t => { | ||
const server = t.context.server; | ||
return t.throws(() => { | ||
@@ -26,3 +33,4 @@ server.route({ | ||
test('throw for missing model', (t) => { | ||
test('throw for missing model', t => { | ||
const server = t.context.server; | ||
return t.throws(() => { | ||
@@ -39,3 +47,4 @@ server.route({ | ||
test('throw for invalid options', (t) => { | ||
test('throw for invalid options', t => { | ||
const server = t.context.server; | ||
return t.throws(() => { | ||
@@ -52,3 +61,4 @@ server.route({ | ||
test('register a getOne handler', (t) => { | ||
test('register a getOne handler', t => { | ||
const server = t.context.server; | ||
server.route({ | ||
@@ -66,3 +76,4 @@ method: 'GET', | ||
test('register a getAll handler', (t) => { | ||
test('register a getAll handler', t => { | ||
const server = t.context.server; | ||
server.route({ | ||
@@ -80,3 +91,4 @@ method: 'GET', | ||
test('register a post handler', (t) => { | ||
test('register a post handler', t => { | ||
const server = t.context.server; | ||
server.route({ | ||
@@ -94,3 +106,4 @@ method: 'POST', | ||
test('register a patch handler', (t) => { | ||
test('register a patch handler', t => { | ||
const server = t.context.server; | ||
server.route({ | ||
@@ -108,3 +121,4 @@ method: 'PATCH', | ||
test('register a put handler', (t) => { | ||
test('register a put handler', t => { | ||
const server = t.context.server; | ||
server.route({ | ||
@@ -111,0 +125,0 @@ method: 'PUT', |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
177936
27
636
162
12