@getanthill/datastore
Version:
Event-Sourced Datastore
145 lines • 5.88 kB
JavaScript
"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