UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

145 lines 5.88 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAPIMiddleware = void 0; const api_validators_1 = require("@getanthill/api-validators"); const express_1 = __importDefault(require("express")); const cloneDeep_1 = __importDefault(require("lodash/cloneDeep")); const builder_1 = require("../spec/builder"); const spec_1 = require("../spec"); class OpenAPIMiddleware { constructor(config, builder) { this.config = config; this.validator = new api_validators_1.Validator(spec_1.SPEC_FRAGMENT); this.builder = builder; this.services = this.config.services; this.updateValidator(this.config.specification); } check(specification) { var _a, _b; try { this.validator.validateSpecification(specification); } catch (err) { if (this.config.warnOnInvalidSpecificationOnly !== true) { throw err; } (_b = (_a = this.config.telemetry) === null || _a === void 0 ? void 0 : _a.logger) === null || _b === void 0 ? void 0 : _b.warn('[OpenAPI] Invalid specification', { err, }); } return true; } updateValidator(specification) { this.check(specification); this.validator.updateSpecification(specification); this.validator.reset().initAjv({ useDefaults: true, coerceTypes: false, strictTypes: false, strict: false, }, { useDefaults: true, coerceTypes: 'array', strictTypes: false, strict: false, }); this.validator.compile(); return specification; } async update(specification) { if (specification) { return this.updateValidator(specification); } if (typeof this.builder === 'function') { const _specification = await this.builder(); return this.updateValidator(_specification); } } /** * Returns the definition and * * @param {string[]} tokens * @returns {callback} The middleware */ spec() { return (req, res, next) => { var _a, _b; const definition = (0, cloneDeep_1.default)(this.validator.getSpecification()); const filteredModels = (req.query.models || []); if (filteredModels.length > 0) { const schemas = ((_a = definition.components) === null || _a === void 0 ? void 0 : _a.schemas) || {}; const paths = definition.paths; const tags = (_b = definition.tags) !== null && _b !== void 0 ? _b : []; definition.paths = {}; definition.tags = []; definition.components = { ...definition.components, schemas: {} }; for (const tag of tags) { /* @ts-ignore */ if (filteredModels.includes(tag.name.toLowerCase())) { definition.tags.push(tag); } } for (const k in paths) { const model = k.slice(1).split('/').shift(); if (model && filteredModels.includes(model)) { const entityName = (0, builder_1.getEntityName)(model, true); definition.paths[k] = paths[k]; definition.components.schemas[entityName] = schemas[entityName]; } } } res.set('content-type', 'application/json'); res.send(api_validators_1.Validator.replaceReferencesInSpecification(definition, '')); }; } registerInputValidation() { const router = express_1.default.Router(); // Dynamic reload the API Specification: if (this.builder !== null) { router.get(`/${this.config.secret}`, async (req, res, next) => { await this.update(); next(); }); } router .get(`/${this.config.secret}`, this.spec()) .use(this.validator.validateRequestMiddleware(true)); return router; } validateResponseMiddleware() { return (req, res, next) => { var _a, _b; const errors = this.validator.validateResponse(req, res); if (errors.length) { const err = { status: 501, message: 'Response validation error', details: errors, }; res.locals.meter && res.locals.meter({ state: '501', ...res.locals.attributes }); res.locals.tic && ((_a = this.services) === null || _a === void 0 ? void 0 : _a.metrics.recordHttpRequestDuration(Date.now() - res.locals.tic, { status: '501', method: req.method, model: res.locals.model })); res.status(501).json(err); return; } res.locals.meter && res.locals.meter({ state: '200', ...res.locals.attributes }); res.locals.tic && ((_b = this.services) === null || _b === void 0 ? void 0 : _b.metrics.recordHttpRequestDuration(Date.now() - res.locals.tic, { status: '200', method: req.method, model: res.locals.model })); // @ts-ignore res.json(res.body); return; }; } registerOutputValidation() { const router = express_1.default.Router(); router.use(this.validateResponseMiddleware()); return router; } } exports.OpenAPIMiddleware = OpenAPIMiddleware; //# sourceMappingURL=OpenApi.js.map