express-openapi-validator
express-openapi-validator copied to clipboard
Separate out validation from express
I'm using a framework (AWS API gateway) that isn't one that is supported directly, and while I'm not asking for that framework to be supported, there is a lot of great functionality that I want to reuse, but can't really.
Luckily there is a workaround, but isn't great as it still loads a ton of unnecessary functionality, causing slowness ~80ms of unnecessary delay on initial load.
The solution
Separate the middlewares to their own package with the configuration, and have the express-openapi-validator
, depend on that (instead of openapi-core
)
In the meantime we've written this:
const { OpenApiValidator } = require('express-openapi-validator/dist/openapi.validator');
const { OpenApiSpecLoader } = require('express-openapi-validator/dist/framework/openapi.spec.loader');
const { cloneDeep } = require('lodash');
const spec = require('./openapi');
const logger = require('./requestLogger');
const oav = new OpenApiValidator({ apiSpec: spec, validateResponses: false, validateApiSpec: false, validateSecurity: false, validateRequests: { allowUnknownQueryParameters: false } });
const compiledSpec = new OpenApiSpecLoader({ apiDoc: cloneDeep(spec), validateApiSpec: false, $refParser: { mode: 'dereference' } }).load();
const requestValidationFunction = oav.installMiddleware(compiledSpec).find(m => m.name === 'requestMiddleware');
class ModelValidator {
async validate(request) {
const resolvedSpec = await compiledSpec;
const schema = resolvedSpec.apiDoc.paths[request.route] && resolvedSpec.apiDoc.paths[request.route][request.httpMethod.toLowerCase()];
if (!schema) {
return;
}
const newRequest = {
originalUrl: request.path,
method: request.httpMethod,
headers: Object.assign({ 'content-type': 'application/json' }, request.headers || {}),
query: request.queryStringParameters,
body: request.body,
params: request.pathParameters,
openapi: {
expressRoute: request.route.replace(/{([^}]+)}/g, ':$1'),
schema: schema,
pathParams: {}
}
};
await requestValidationFunction(newRequest, {}, error => {
if (error) {
const wrapped = Error.create({ title: `Request ${error.errors[0].path} ${error.errors[0].message}.` });
wrapped.code = 'InvalidInputRequest';
throw wrapped;
}
});
return;
}
Any wisdom on improvements would be appreciated.