apeman-app-rest
Version:
apeman app to handle restful endpoint.
209 lines (186 loc) • 5.85 kB
JavaScript
/**
* apeman app to handle restful endpoint.
* @function apemanAppRest
* @param {object} models - Model objects.
* @param {object} [options] - Optional settings.
* @param {function} [options.pathname='/'+apemanmodel.toType(model)] - Spec path name.
* @param {Endpoint|boolean} [options.knock]
* @param {Endpoint|boolean} [options.spec]
* @param {Endpoint|boolean} [options.list]
* @param {Endpoint|boolean} [options.create]
* @param {Endpoint|boolean} [options.bulkUpdate]
* @param {Endpoint|boolean} [options.bulkDestroy]
* @param {Endpoint|boolean} [options.one]
* @param {Endpoint|boolean} [options.update]
* @param {Endpoint|boolean} [options.destroy]
* @param {Endpoint|boolean} [options.relatedList]
* @param {Endpoint|boolean} [options.relatedCreate]
* @param {Endpoint|boolean} [options.relatedUpdateBulk]
* @param {Endpoint|boolean} [options.relatedDestroyBulk]
* @param {Endpoint|boolean} [options.relatedOne]
* @param {Endpoint|boolean} [options.relatedUpdate]
* @param {Endpoint|boolean} [options.relatedDestroy]
* @param {Endpoint|boolean} [options.relationList]
* @param {Endpoint|boolean} [options.relationCreate]
* @param {Endpoint|boolean} [options.relationUpdate]
* @param {Endpoint|boolean} [options.relationDestroy]
* @returns {function} - Defined app function.
*/
/**
* @typedef {Object} Endpoint
* @property {function} handle - Handler function
* @property {Object} schema - Validation schema
*/
const route = require('apeman-app-route')
const restSpec = require('./specifying/rest_spec')
const assert = require('assert')
const co = require('co')
const defaults = require('defaults')
const apemanmodel = require('apemanmodel')
const restRoute = require('./routing/rest_route')
const {
CreateEndpoint,
DestroyEndpoint,
Endpoint,
ListEndpoint,
OneEndpoint,
RelatedCreateEndpoint,
RelatedDestroyEndpoint,
RelatedListEndpoint,
RelatedOneEndpoint,
RelatedUpdateEndpoint,
RelationCreateEndpoint,
RelationDestroyEndpoint,
RelationListEndpoint,
RelationUpdateEndpoint,
UpdateEndpoint,
SpecEndpoint
} = require('./endpoints')
const {
BulkCreateEndpoint,
BulkDestroyEndpoint,
BulkRelatedCreateEndpoint,
BulkRelatedDestroyEndpoint,
BulkRelatedUpdateEndpoint,
BulkRelationCreateEndpoint,
BulkRelationDestroyEndpoint,
BulkUpdateEndpoint
} = require('./endpoints/bulk')
const debug = require('debug')('apeman:app:rest')
/** @lends create */
function create (model, options = {}) {
assert.ok(model, 'model is required.')
debug(`Register rest for model: ${model}`)
let type = apemanmodel.toType(model)
let pathname = String(options.pathname || `/${type}`).replace(/\/$/, '')
let { associations } = model
let {
knock,
spec,
list,
create,
bulkUpdate,
bulkDestroy,
one,
update,
destroy,
relatedList,
relatedCreate,
relatedUpdateBulk,
relatedDestroyBulk,
relatedOne,
relatedUpdate,
relatedDestroy,
relationList,
relationCreate,
relationUpdate,
relationDestroy
} = defaults(options, {})
let rest = restRoute.bind(restRoute, model)
let routes = {
[`${pathname || '/'}`]: {
'HEAD': rest('knock', knock, true),
'OPTIONS': rest('spec', spec, new SpecEndpoint({ pathname })),
'GET': rest('list', list, new ListEndpoint({}), {}),
'POST': rest('create', create, new CreateEndpoint({})),
'PATCH': rest('bulkUpdate', bulkUpdate, new BulkUpdateEndpoint({})),
'DELETE': rest('bulkDestroy', bulkDestroy, new BulkDestroyEndpoint({}))
},
[`${pathname}/:id`]: {
'GET': rest('one', one, new OneEndpoint({})),
'PATCH': rest('update', update, new UpdateEndpoint({})),
'DELETE': rest('destroy', destroy, new DestroyEndpoint({}))
}
}
for (let name of Object.keys(associations || {})) {
let association = associations[ name ]
let associate = co.wrap(function * associate (ctx, next) {
ctx.state.association = association
yield next()
})
routes[ `${pathname}/:id/${name}` ] = {
'GET': [
associate,
...rest('relatedList', relatedList, new RelatedListEndpoint({}))
],
'POST': [
associate,
...rest('relatedCreate', relatedCreate, new RelatedCreateEndpoint({}))
],
'PATCH': [
associate,
...rest('relatedUpdateBulk', relatedUpdateBulk, new BulkRelatedUpdateEndpoint({})),
],
'DELETE': [
associate,
...rest('relatedDestroyBulk', relatedDestroyBulk, new BulkRelatedDestroyEndpoint({}))
]
}
routes[ `${pathname}/:id/${name}/:related_id` ] = {
'GET': [
associate,
...rest('relatedOne', relatedOne, new RelatedOneEndpoint({}))
],
'PATCH': [
associate,
...rest('relatedUpdate', relatedUpdate, new RelatedUpdateEndpoint({}))
],
'DELETE': [
associate,
...rest('relatedDestroy', relatedDestroy, new RelatedDestroyEndpoint({}))
]
}
routes[ `${pathname}/:id/relationships/${name}` ] = {
'GET': [
associate,
...rest('relationList', relationList, new RelationListEndpoint({}))
],
'POST': [
associate,
...rest('relationCreate', relationCreate, new RelationCreateEndpoint({}))
],
'PATCH': [
associate,
...rest('relationUpdate', relationUpdate, new RelationUpdateEndpoint({}))
],
'DELETE': [
associate,
...rest('relationDestroy', relationDestroy, new RelationDestroyEndpoint({}))
]
}
}
let app = route(routes)
Object.assign(app, {
/**
* Application description.
*/
$desc: 'Restful endpoint.',
/**
* Endpoint specification.
*/
$spec: restSpec(model, { pathname })
})
return app
}
module.exports = create