UNPKG

apeman-app-rest

Version:
117 lines (107 loc) 3.32 kB
/** * Define a rest route. * @function restRoute * @returns {Array.<function>} */ 'use strict' const assert = require('assert') const co = require('co') const validate = require('apeman-app-validate') const { defineOne } = require('apemanmodel') const parseQuery = require('../parsing/parse_query') const parseParams = require('../parsing/parse_params') const parseBody = require('../parsing/parse_body') /** @lends restRoute */ function restRoute (model, name, ...endpoints) { assert.ok(model, 'model is required.') assert.ok(name, 'name is required.') let db = model.getDB() return [ co.wrap(function * knock (ctx, next) { ctx.set('ap-action', name) Object.assign(ctx.state, { name, model }, parseBody(ctx.request.body), parseParams(ctx.params), parseQuery(ctx.request.querystring) ) yield next() }), co.wrap(function * applyTransaction (ctx, next) { if (!db) { yield next() return } let transactionId = ctx.headers[ 'ap-transaction-id' ] let transaction = transactionId ? db.getTransaction(transactionId) : null if (transaction) { ctx.state.transaction = transaction yield next() } else { yield new Promise((resolve, reject) => db.transaction((transaction) => co(function * withTransaction () { ctx.state.transaction = transaction yield next() }).then(resolve, reject) )) } }), co.wrap(function * instanceById (ctx, next) { if (!db) { yield next() return } let { id, model, transaction } = ctx.state if (typeof id !== 'undefined') { let one = defineOne(model, transaction) ctx.state.instance = yield one(id) } yield next() }), ...endpoints .map((endpoint) => { let stop = (endpoint === false) if (stop) { return (ctx) => {} } let skip = (endpoint === true) || (typeof endpoint === 'undefined') if (skip) { return null } if (typeof endpoint === 'function') { return restRoute.wrapHandle(endpoint) } else { let { handle, schema, singleton } = endpoint return [ singleton ? restRoute.registerSingleton() : null, handle ? restRoute.wrapHandle(handle.bind(endpoint)) : null, schema ? validate(schema) : null ].filter((handler) => !!handler) } }) .reduce((handlers, handler) => handlers.concat(handler), []) .filter((handler) => !!handler), (ctx) => {} // Flush response ].reduce((route, handler) => route.concat(handler), []) } Object.assign(restRoute, { registerSingleton () { return co.wrap(function * rest (ctx, next) { let id = 'singleton' let { state } = ctx let invalidId = state && state.id && (state.id !== id) if (invalidId) { throw new Error(`Invalid id detected for singleton endpoint: ${state.id}`) } ctx.state = Object.assign(state, { id }) yield next() }) }, wrapHandle (handle) { return co.wrap(function * rest (ctx, next) { yield Promise.resolve(handle(ctx, next)) }) } }) module.exports = restRoute