Socket
Socket
Sign inDemoInstall

cf-crud-service-api-builder

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cf-crud-service-api-builder - npm Package Compare versions

Comparing version 0.1.3 to 0.5.0

test/events.test.js

38

api-builder.js
module.exports = buildApi
var routes =
{ get: require('./endpoints/get')
, post: require('./endpoints/post')
, put: require('./endpoints/put')
, patch: require('./endpoints/patch')
, 'delete': require('./endpoints/delete')
}
{ get: require('./endpoints/get')
, post: require('./endpoints/post')
, put: require('./endpoints/put')
, patch: require('./endpoints/patch')
, 'delete': require('./endpoints/delete')
}
, EventEmitter = require('events').EventEmitter
, createPipe = require('piton-pipe').createPipe
function buildApi(service, urlRoot, router, logger, middleware, verbs) {
function Api() { EventEmitter.call(this) }
Api.prototype = Object.create(EventEmitter.prototype)
var hooks =
{ 'create:request': createPipe()
, 'create:response': createPipe()
, 'read:response': createPipe()
, 'update:request': createPipe()
, 'update:response': createPipe()
, 'partialUpdate:request': createPipe()
, 'partialUpdate:response': createPipe()
}
Api.prototype.hook = function (name, fn) {
if (!hooks[name]) throw new Error('No hook exists for: ' + name)
hooks[name].add(fn)
}
var api = new Api()
if (!Array.isArray(middleware) && typeof middleware !== 'function') throw new Error('Middleware is not defined')

@@ -20,5 +42,7 @@

verbs.forEach(function (verb) {
routes[verb](service, urlRoot, router, logger, middleware)
routes[verb](service, urlRoot, router, logger, middleware, api.emit.bind(api), hooks)
})
return api
}

5

endpoints/delete.js
module.exports = del
function del(service, urlRoot, router, logger, middleware) {
function del(service, urlRoot, router, logger, middleware, emit) {

@@ -15,3 +15,4 @@ router.delete(urlRoot + '/:id', middleware, function (req, res) {

} else {
res.send(204)
emit('delete', req)
res.sendStatus(204)
}

@@ -18,0 +19,0 @@ })

@@ -6,3 +6,3 @@ module.exports = get

function get(service, urlRoot, router, logger, middleware) {
function get(service, urlRoot, router, logger, middleware, emit, hooks) {

@@ -16,3 +16,9 @@ router.get(urlRoot + '/:id', middleware, function (req, res) {

if (!entity) return res.status(404).json({ status: 'Not found' })
res.json(entity)
hooks['read:response'].run(entity, function (error, postHookEntity) {
if (error) {
var message = 'Error running response hook for "' + service.name + '" service'
return res.status(400).json({ error: message })
}
res.status(200).json(postHookEntity)
})
})

@@ -45,8 +51,15 @@ })

}
res.json(
{ results: data
, page: req.query.pagination.page
, pageSize: req.query.pagination.pageSize
, totalItems: count
})
hooks['read:response'].run(data, function (error, postHookData) {
if (error) {
var message = 'Error running response hook for "' + service.name + '" service'
return res.status(400).json({ error: message })
}
res.json(
{ results: postHookData
, page: req.query.pagination.page
, pageSize: req.query.pagination.pageSize
, totalItems: count
})
})
})

@@ -53,0 +66,0 @@ })

module.exports = patch
function patch(service, urlRoot, router, logger, middleware) {
function patch(service, urlRoot, router, logger, middleware, emit, hooks) {

@@ -8,11 +8,20 @@ router.patch(urlRoot + '/:id', middleware, function (req, res) {

req.body._id = req.params.id
service.partialUpdate(req.body, {}, function (error, updatedObject) {
if (error) {
res.status(400).json(error)
} else {
res.status(200).json(updatedObject)
}
hooks['partialUpdate:request'].run(req.body, function (error, postHookBody) {
if (error) return res.status(400).json(error)
service.partialUpdate(postHookBody, {}, function (error, updatedObject) {
if (error) {
res.status(400).json(error)
} else {
emit('partialUpdate', req, updatedObject)
hooks['partialUpdate:response'].run(updatedObject, function (error, postHookUpdatedObject) {
if (error) return res.status(400).json(error)
res.status(200).json(postHookUpdatedObject)
})
}
})
})
})
}
module.exports = post
function post(service, urlRoot, router, logger, middleware) {
function post(service, urlRoot, router, logger, middleware, emit, hooks) {
router.post(urlRoot, middleware, function (req, res) {
logger.debug('POST received', JSON.stringify(req.body))
service.create(req.body, function (error, newObject) {
if (error) {
res.status(400).json(error)
} else {
res.status(201).json(newObject)
}
hooks['create:request'].run(req.body, function (error, postHookBody) {
if (error) return res.status(400).json(error)
service.create(postHookBody, function (error, newObject) {
if (error) {
res.status(400).json(error)
} else {
emit('create', req, newObject)
hooks['create:response'].run(newObject, function (error, postHookNewObject) {
if (error) return res.status(400).json(error)
res.status(201).json(postHookNewObject)
})
}
})
})

@@ -14,0 +21,0 @@ })

@@ -6,3 +6,3 @@ module.exports = put

function put(service, urlRoot, router, logger, middleware) {
function put(service, urlRoot, router, logger, middleware, emit, hooks) {

@@ -35,2 +35,3 @@ // Optional :id url param to allow for arrays to be PUT

} else {
emit('update', req, updatedObject)
cb(null, updatedObject)

@@ -41,9 +42,16 @@ }

async.map(req.body, update, function (error, updatedObjects) {
var status = updateError ? 400 : 200
// If array has a length of 1 then only return first item
res.status(status).json(updatedObjects.length === 1 ? updatedObjects[0] : updatedObjects)
hooks['update:request'].run(req.body, function (error, postHookBody) {
if (error) return res.status(400).json(error)
async.map(postHookBody, update, function (error, updatedObjects) {
var status = updateError ? 400 : 200
hooks['update:response'].run(updatedObjects, function (error, postHookUpdatedObject) {
if (error) return res.status(400).json(error)
// If array has a length of 1 then only return first item
res.status(status).json(postHookUpdatedObject.length === 1 ? postHookUpdatedObject[0] : postHookUpdatedObject)
})
})
})
})
}

@@ -10,18 +10,18 @@ module.exports = createFilterParser

, ignoredTypes = [ Object, Array ]
, type = null
, type = getType(key, parentKey)
if (parentKey) {
type = schema.schema[parentKey].type
} else {
type = schema.schema[key].type
}
// Skip ignored types and Schemata Arrays
if (ignoredTypes.indexOf(type) === -1 && !type.arraySchema) {
if (Array.isArray(value)) {
var newValue = []
value.forEach(function (item) {
newValue.push(schema.castProperty(type, item))
if (isMongoOperator(key) && Array.isArray(value)) {
value = value.map(function (item) {
// Recursively cast objects like `{ $in: [1, 2, 3 }`
if (typeof item === 'object' && null !== item) return parseObject(item)
// Do a simple cast if they arent objects
return schema.castProperty(type, item)
})
value = newValue
} else if (Array.isArray(value)) {
value = value.map(function (item) {
return schema.castProperty(type, item)
})
} else if (typeof value === 'object' && null !== value) {

@@ -38,3 +38,18 @@ value = parseObject(value, key)

function getType(key, parentKey) {
if (parentKey) {
return schema.schema[parentKey].type
} else if (isMongoOperator(key)) {
return {}
} else {
return schema.schema[key].type
}
}
// Key starts with $ e.g. $or, $and
function isMongoOperator(key) {
return key.match(/^\$/)
}
return parseObject
}

@@ -5,3 +5,3 @@ {

"description": "Build an HTTP API for a crud-service",
"version": "0.1.3",
"version": "0.5.0",
"tags": [],

@@ -27,16 +27,19 @@ "repository": {

"dependencies": {
"lodash.assign": "^2.4.1"
"async": "^1.5.0",
"lodash.assign": "^3.2.0",
"piton-pipe": "0.0.4"
},
"devDependencies": {
"async": "^0.9.0",
"crud-service": "^0.1.0",
"express": "^3.18.4",
"istanbul": "0",
"jshint": "2",
"mocha": "1",
"save": "0.0.20",
"schemata": "^2.0.2",
"supertest": "^0.15.0",
"validity": "0.0.3"
"body-parser": "^1.14.2",
"crud-service": "^0.2.0",
"express": "^4.13.3",
"istanbul": "^0.4.1",
"jshint": "^2.9.1-rc1",
"mc-logger": "0.0.0",
"mocha": "^2.3.4",
"save": "^2.1.1",
"schemata": "^3.0.0",
"supertest": "^1.1.0",
"validity": "^0.0.3"
}
}

@@ -21,2 +21,48 @@ # cf-crud-service-api-builder

### Hooks
When using the api builder, you can hook into certain actions to manipulate the request data before it is sent to the database or the response data before it is sent to the requester.
```js
var api = crudServiceApiBuilder(service, '/article', router, logger, middleware)
api.hook('create:request', function (data, cb) {
// do whatever you like with the data
cb(null, data)
})
```
Supported hooks are:
* `create:request`
* `create:response`
* `read:response`
* `update:request`
* `update:response`
* `partialUpdate:request`
* `partialUpdate:response`
### Events
When using the api builder, you can listen for certain events so that you can add hooks to perform your own actions after a request has been succesful. e.g
```js
var api = crudServiceApiBuilder(service, '/article', router, logger, middleware)
api.on('create', function (req, newArticle) {
// do whatever you like with the req and article object
})
```
Supported events are:
* `create`
* `update`
* `partialUpdate`
* `delete`
## Credits

@@ -23,0 +69,0 @@ Built by developers at [Clock](http://clock.co.uk).

@@ -5,3 +5,3 @@ var createGetEndpoint = require('../../endpoints/get')

, request = require('supertest')
, logger = { debug: noop, info: noop, warn: noop, error: noop }
, logger = require('mc-logger')
, assert = require('assert')

@@ -11,7 +11,8 @@ , async = require('async')

, qs = require('querystring')
, createPipe = require('piton-pipe').createPipe
function noop() {}
describe('GET endpoint', function () {
var hooks = { 'read:response': createPipe() }
describe('GET /prefix/:id', function () {

@@ -28,3 +29,3 @@

var app = express()
createGetEndpoint(service, '/things', app, logger, [])
createGetEndpoint(service, '/things', app, logger, [], null, hooks)
request(app)

@@ -42,3 +43,3 @@ .get('/things/1')

var app = express()
createGetEndpoint(service, '/things', app, logger, [])
createGetEndpoint(service, '/things', app, logger, [], null, hooks)
request(app)

@@ -88,3 +89,3 @@ .get('/things/2')

var app = express()
createGetEndpoint(service, '/things', app, logger, [])
createGetEndpoint(service, '/things', app, logger, [], null, hooks)
request(app)

@@ -128,3 +129,3 @@ .get('/things')

var app = express()
createGetEndpoint(service, '/things', app, logger, [])
createGetEndpoint(service, '/things', app, logger, [], null, hooks)
request(app)

@@ -131,0 +132,0 @@ .get('/things?' + qs.stringify({ pagination: JSON.stringify({ page: 3, pageSize: 7 }) }))

@@ -69,2 +69,21 @@ var schemata = require('schemata')

it('should not throw for keys that start with $', function () {
assert.doesNotThrow(function () {
var params = { $or: [] }
params = filterParser(params)
}, /Cannot read property 'type' of undefined/)
})
it('should work for keys that start with $', function () {
var params = { $or: [ { string: 1 } ] }
params = filterParser(params)
assert.equal(typeof params.$or[0].string, 'string')
})
it('should recursively for keys that start with $', function () {
var params = { $or: [ { string: { $in: [1] } }, { string: { $size: 0 } } ] }
params = filterParser(params)
assert.equal(params.$or[0].string.$in[0], '1')
assert.equal(params.$or[1].string.$size, '0')
})
})

@@ -71,0 +90,0 @@

@@ -7,6 +7,4 @@ module.exports = createService

, validity = require('validity')
, logger = { debug: noop, info: noop, warn: noop, error: noop }
, logger = require('mc-logger')
function noop() {}
function createService() {

@@ -13,0 +11,0 @@ return new Service('thing', save('thing', { logger: logger }), createSchema())

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc