UNPKG

arrest

Version:

OpenAPI v3 compliant REST framework for Node.js, with support for MongoDB and JSON-Schema

101 lines 3.5 kB
import camelcase from 'camelcase'; import decamelize from 'decamelize'; import { Router } from 'express'; import { API } from './api.js'; import { Operation, SimpleOperation } from './operation.js'; export class Resource { constructor(info = {}, routes) { this.info = info; this.operations = []; if (this.info.routes) { if (routes) { throw new Error('double routes specification'); } routes = this.info.routes; delete this.info.routes; } this.initInfo(); if (routes) { for (let path in routes) { let handlers = routes[path]; for (let method in handlers) { this.addOperation(path, method, handlers[method]); } } } } initInfo() { if (!this.info.name) { this.info.name = Resource.capitalize(camelcase(this.constructor.name)); } if (!this.info.namePlural) { this.info.namePlural = this.info.name + 's'; } } get basePath() { return '/' + (this.info.path ? this.info.path : decamelize('' + this.info.namePlural, { separator: '-' })); } get scopeDescription() { return `Unrestricted access to all ${this.info.namePlural}`; } addOperation(pathOrOp, method, handler, id) { let op; if (typeof pathOrOp === 'string') { if (!method) { throw new Error('invalid method'); } else if (!handler) { throw new Error('invalid handler, must be an Operation constructor or an express RequestHandler'); } else if (Operation.prototype === handler.prototype || Operation.prototype.isPrototypeOf(handler.prototype)) { op = new handler(this, pathOrOp, method); } else { op = new SimpleOperation(handler, this, pathOrOp, method, id); } } else { op = pathOrOp; } this.operations.push(op); return this; } attach(api) { this.api = api; let tag = { name: '' + this.info.name, }; if (this.info.description) tag.description = this.info.description; if (this.info.externalDocs) tag.externalDocs = this.info.externalDocs; if (this.info.id) tag['x-id'] = this.info.id; if (this.info.title) tag['x-title'] = this.info.title; if (this.info.summaryFields) tag['x-summary-fields'] = this.info.summaryFields; api.registerTag(tag); api.registerOauth2Scope('' + this.info.name, this.scopeDescription); this.operations.forEach((op) => op.attach(api)); } async router(base, options) { let r = Router(options); let knownPaths = new Set(); for (let op of this.operations) { knownPaths.add(op.path); await op.router(r); } knownPaths.forEach((path) => { r.all(path, (req, res, next) => { next(API.newError(405, 'Method Not Allowed', "The API Endpoint doesn't support the specified HTTP method for the given resource")); }); }); base.use(this.basePath, r); return r; } static capitalize(s) { return s.charAt(0).toUpperCase() + s.slice(1); } } //# sourceMappingURL=resource.js.map