routing-controllers-openapi
Version:
Runtime OpenAPI v3 spec generation for routing-controllers
273 lines • 23.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.expressToOpenAPIPath = exports.getTags = exports.getSummary = exports.getSpec = exports.getResponses = exports.getStatusCode = exports.getContentType = exports.getRequestBody = exports.getQueryParams = exports.getPathParams = exports.getHeaderParams = exports.getPaths = exports.getOperationId = exports.getOperation = exports.getFullPath = exports.getFullExpressPath = void 0;
const tslib_1 = require("tslib");
const lodash_merge_1 = tslib_1.__importDefault(require("lodash.merge"));
const lodash_capitalize_1 = tslib_1.__importDefault(require("lodash.capitalize"));
const lodash_startcase_1 = tslib_1.__importDefault(require("lodash.startcase"));
const oa = tslib_1.__importStar(require("openapi3-ts"));
const pathToRegexp = tslib_1.__importStar(require("path-to-regexp"));
require("reflect-metadata");
const decorators_1 = require("./decorators");
function getFullExpressPath(route) {
const { action, controller, options } = route;
return ((options.routePrefix || '') +
(controller.route || '') +
(action.route || ''));
}
exports.getFullExpressPath = getFullExpressPath;
function getFullPath(route) {
return expressToOpenAPIPath(getFullExpressPath(route));
}
exports.getFullPath = getFullPath;
function getOperation(route, schemas) {
const operation = {
operationId: getOperationId(route),
parameters: [
...getHeaderParams(route),
...getPathParams(route),
...getQueryParams(route, schemas),
],
requestBody: getRequestBody(route) || undefined,
responses: getResponses(route),
summary: getSummary(route),
tags: getTags(route),
};
const cleanedOperation = Object.entries(operation)
.filter(([_, value]) => value && (value.length || Object.keys(value).length))
.reduce((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});
return (0, decorators_1.applyOpenAPIDecorator)(cleanedOperation, route);
}
exports.getOperation = getOperation;
function getOperationId(route) {
return `${route.action.target.name}.${route.action.method}`;
}
exports.getOperationId = getOperationId;
function getPaths(routes, schemas) {
const routePaths = routes.map((route) => ({
[getFullPath(route)]: {
[route.action.type]: getOperation(route, schemas),
},
}));
return (0, lodash_merge_1.default)(...routePaths);
}
exports.getPaths = getPaths;
function getHeaderParams(route) {
const headers = route.params
.filter((p) => p.type === 'header')
.map((headerMeta) => {
const schema = getParamSchema(headerMeta);
return {
in: 'header',
name: headerMeta.name || '',
required: isRequired(headerMeta, route),
schema,
};
});
const headersMeta = route.params.find((p) => p.type === 'headers');
if (headersMeta) {
const schema = getParamSchema(headersMeta);
headers.push({
in: 'header',
name: schema.$ref.split('/').pop() || '',
required: isRequired(headersMeta, route),
schema,
});
}
return headers;
}
exports.getHeaderParams = getHeaderParams;
function getPathParams(route) {
const path = getFullExpressPath(route);
const tokens = pathToRegexp.parse(path);
return tokens
.filter((token) => token && typeof token === 'object')
.map((token) => {
const name = token.name + '';
const param = {
in: 'path',
name,
required: token.modifier !== '?',
schema: { type: 'string' },
};
if (token.pattern && token.pattern !== '[^\\/]+?') {
param.schema = { pattern: token.pattern, type: 'string' };
}
const meta = route.params.find((p) => p.name === name && p.type === 'param');
if (meta) {
const metaSchema = getParamSchema(meta);
param.schema =
'type' in metaSchema ? Object.assign(Object.assign({}, param.schema), metaSchema) : metaSchema;
}
return param;
});
}
exports.getPathParams = getPathParams;
function getQueryParams(route, schemas) {
var _a;
const queries = route.params
.filter((p) => p.type === 'query')
.map((queryMeta) => {
const schema = getParamSchema(queryMeta);
return {
in: 'query',
name: queryMeta.name || '',
required: isRequired(queryMeta, route),
schema,
};
});
const queriesMeta = route.params.find((p) => p.type === 'queries');
if (queriesMeta) {
const paramSchema = getParamSchema(queriesMeta);
const paramSchemaName = paramSchema.$ref.split('/').pop() || '';
const currentSchema = schemas[paramSchemaName];
if (oa.isSchemaObject(currentSchema)) {
for (const [name, schema] of Object.entries((currentSchema === null || currentSchema === void 0 ? void 0 : currentSchema.properties) || {})) {
queries.push({
in: 'query',
name,
required: (_a = currentSchema.required) === null || _a === void 0 ? void 0 : _a.includes(name),
schema,
});
}
}
}
return queries;
}
exports.getQueryParams = getQueryParams;
function getNamedParamSchema(param) {
const { type } = param;
if (type === 'file') {
return { type: 'string', format: 'binary' };
}
if (type === 'files') {
return {
type: 'array',
items: {
type: 'string',
format: 'binary',
},
};
}
return getParamSchema(param);
}
function getRequestBody(route) {
const bodyParamMetas = route.params.filter((d) => d.type === 'body-param');
const uploadFileMetas = route.params.filter((d) => ['file', 'files'].includes(d.type));
const namedParamMetas = [...bodyParamMetas, ...uploadFileMetas];
const namedParamsSchema = namedParamMetas.length > 0
? namedParamMetas.reduce((acc, d) => (Object.assign(Object.assign({}, acc), { properties: Object.assign(Object.assign({}, acc.properties), { [d.name]: getNamedParamSchema(d) }), required: isRequired(d, route)
? [...(acc.required || []), d.name]
: acc.required })), { properties: {}, required: [], type: 'object' })
: null;
const contentType = uploadFileMetas.length > 0 ? 'multipart/form-data' : 'application/json';
const bodyMeta = route.params.find((d) => d.type === 'body');
if (bodyMeta) {
const bodySchema = getParamSchema(bodyMeta);
const items = 'items' in bodySchema && bodySchema.items ? bodySchema.items : bodySchema;
const $ref = oa.isReferenceObject(items) ? items.$ref : '';
return {
content: {
[contentType]: {
schema: namedParamsSchema
? { allOf: [bodySchema, namedParamsSchema] }
: bodySchema,
},
},
description: ($ref || '').split('/').pop(),
required: isRequired(bodyMeta, route),
};
}
else if (namedParamsSchema) {
return {
content: { [contentType]: { schema: namedParamsSchema } },
};
}
}
exports.getRequestBody = getRequestBody;
function getContentType(route) {
const defaultContentType = route.controller.type === 'json'
? 'application/json'
: 'text/html; charset=utf-8';
const contentMeta = route.responseHandlers.find((h) => h.type === 'content-type');
return contentMeta ? contentMeta.value : defaultContentType;
}
exports.getContentType = getContentType;
function getStatusCode(route) {
const successMeta = route.responseHandlers.find((h) => h.type === 'success-code');
return successMeta ? successMeta.value + '' : '200';
}
exports.getStatusCode = getStatusCode;
function getResponses(route) {
const contentType = getContentType(route);
const successStatus = getStatusCode(route);
return {
[successStatus]: {
content: { [contentType]: {} },
description: 'Successful response',
},
};
}
exports.getResponses = getResponses;
function getSpec(routes, schemas) {
return {
components: { schemas: {} },
info: { title: '', version: '1.0.0' },
openapi: '3.0.0',
paths: getPaths(routes, schemas),
};
}
exports.getSpec = getSpec;
function getSummary(route) {
return (0, lodash_capitalize_1.default)((0, lodash_startcase_1.default)(route.action.method));
}
exports.getSummary = getSummary;
function getTags(route) {
return [(0, lodash_startcase_1.default)(route.controller.target.name.replace(/Controller$/, ''))];
}
exports.getTags = getTags;
function expressToOpenAPIPath(expressPath) {
const tokens = pathToRegexp.parse(expressPath);
return tokens
.map((d) => (typeof d === 'string' ? d : `${d.prefix}{${d.name}}`))
.join('');
}
exports.expressToOpenAPIPath = expressToOpenAPIPath;
function isRequired(meta, route) {
var _a, _b, _c;
const globalRequired = (_c = (_b = (_a = route.options) === null || _a === void 0 ? void 0 : _a.defaults) === null || _b === void 0 ? void 0 : _b.paramOptions) === null || _c === void 0 ? void 0 : _c.required;
return globalRequired ? meta.required !== false : !!meta.required;
}
function getParamSchema(param) {
const { explicitType, index, object, method } = param;
const type = Reflect.getMetadata('design:paramtypes', object, method)[index];
if (typeof type === 'function' && type.name === 'Array') {
const items = explicitType
? { $ref: '#/components/schemas/' + explicitType.name }
: { type: 'object' };
return { items, type: 'array' };
}
if (explicitType) {
return { $ref: '#/components/schemas/' + explicitType.name };
}
if (typeof type === 'function') {
if (type.prototype === String.prototype ||
type.prototype === Symbol.prototype) {
return { type: 'string' };
}
else if (type.prototype === Number.prototype) {
return { type: 'number' };
}
else if (type.prototype === Boolean.prototype) {
return { type: 'boolean' };
}
else if (type.name !== 'Object') {
return { $ref: '#/components/schemas/' + type.name };
}
}
return {};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVTcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2dlbmVyYXRlU3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0Esd0VBQWlDO0FBQ2pDLGtGQUEyQztBQUMzQyxnRkFBeUM7QUFDekMsd0RBQWlDO0FBQ2pDLHFFQUE4QztBQUM5Qyw0QkFBeUI7QUFHekIsNkNBQW9EO0FBSXBELFNBQWdCLGtCQUFrQixDQUFDLEtBQWE7SUFDOUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLEdBQUcsS0FBSyxDQUFBO0lBQzdDLE9BQU8sQ0FDTCxDQUFDLE9BQU8sQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO1FBQzNCLENBQUMsVUFBVSxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDeEIsQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUNyQixDQUFBO0FBQ0gsQ0FBQztBQVBELGdEQU9DO0FBS0QsU0FBZ0IsV0FBVyxDQUFDLEtBQWE7SUFDdkMsT0FBTyxvQkFBb0IsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO0FBQ3hELENBQUM7QUFGRCxrQ0FFQztBQUtELFNBQWdCLFlBQVksQ0FDMUIsS0FBYSxFQUNiLE9BQThEO0lBRTlELE1BQU0sU0FBUyxHQUF1QjtRQUNwQyxXQUFXLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQztRQUNsQyxVQUFVLEVBQUU7WUFDVixHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUM7WUFDekIsR0FBRyxhQUFhLENBQUMsS0FBSyxDQUFDO1lBQ3ZCLEdBQUcsY0FBYyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUM7U0FDbEM7UUFDRCxXQUFXLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQyxJQUFJLFNBQVM7UUFDL0MsU0FBUyxFQUFFLFlBQVksQ0FBQyxLQUFLLENBQUM7UUFDOUIsT0FBTyxFQUFFLFVBQVUsQ0FBQyxLQUFLLENB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
;