arrest
Version:
OpenAPI v3 compliant REST framework for Node.js, with support for MongoDB and JSON-Schema
101 lines • 3.5 kB
JavaScript
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