Skip to content

Commit

Permalink
fix: #551 unhandled promise rejection on invalid api spec (#556)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdimascio committed Mar 7, 2021
1 parent 68d7059 commit 9314b09
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 12 deletions.
38 changes: 26 additions & 12 deletions src/openapi.validator.ts
@@ -1,5 +1,4 @@
import ono from 'ono';
import ajv = require('ajv');
import * as express from 'express';
import * as _uniq from 'lodash.uniq';
import * as middlewares from './middlewares';
Expand Down Expand Up @@ -93,22 +92,37 @@ export class OpenApiValidator {

installMiddleware(spec: Promise<Spec>): OpenApiRequestHandler[] {
const middlewares: OpenApiRequestHandler[] = [];
const pContext = spec.then((spec) => {
const apiDoc = spec.apiDoc;
const ajvOpts = this.ajvOpts.preprocessor;
const resOpts = this.options.validateResponses as ValidateRequestOpts;
const sp = new SchemaPreprocessor(apiDoc, ajvOpts, resOpts).preProcess();
return {
context: new OpenApiContext(spec, this.options.ignorePaths),
responseApiDoc: sp.apiDocRes,
};
});
const pContext = spec
.then((spec) => {
const apiDoc = spec.apiDoc;
const ajvOpts = this.ajvOpts.preprocessor;
const resOpts = this.options.validateResponses as ValidateRequestOpts;
const sp = new SchemaPreprocessor(
apiDoc,
ajvOpts,
resOpts,
).preProcess();
return {
context: new OpenApiContext(spec, this.options.ignorePaths),
responseApiDoc: sp.apiDocRes,
error: null,
};
})
.catch((e) => {
return {
context: null,
responseApiDoc: null,
error: e,
};
});

let inited = false;
// install path params
middlewares.push((req, res, next) =>
pContext
.then(({ context }) => {
.then(({ context, error }) => {
// Throw if any error occurred during spec load.
if (error) throw error;
if (!inited) {
// Would be nice to pass the current Router object here if the route
// is attach to a Router and not the app.
Expand Down
88 changes: 88 additions & 0 deletions test/invalid.apispec.spec.ts
@@ -0,0 +1,88 @@
import * as express from 'express';
import { Server } from 'http';
import * as request from 'supertest';
import * as OpenApiValidator from '../src';
import { OpenAPIV3, OpenApiValidatorOpts } from '../src/framework/types';
import { startServer } from './common/app.common';

describe('invalid api spec', () => {
it('should propagate spec errors when validateApiSpec is true', async () => {
const apiSpec = createApiSpec();
const app = await createApp({
apiSpec,
});
await request(app).get('/dev/hello/echo').expect(500);
app.server.close();
});
it('should fail gracefully when validateApiSpec is false', async () => {
const apiSpec = createApiSpec();
const app = await createApp({
apiSpec,
validateApiSpec: false,
});
await request(app).get('/dev/hello/echo').expect(500);
app.server.close();
});
});

async function createApp(
opts: OpenApiValidatorOpts,
): Promise<express.Express & { server?: Server }> {
const app = express();

app.use(OpenApiValidator.middleware(opts));
app.use(
express.Router().get('/dev/hello/echo', (req, res) => {
res.status(200).send(req.params.value);
}),
);

await startServer(app, 3001);
return app;
}

function createApiSpec(): OpenAPIV3.Document {
return <any>{
openapi: '3.0.3',
info: {
title: 'The API',
version: '1.0.0',
description: 'Welcome to the API.',
},
servers: [{ url: 'http://localhost:54321/v1', description: 'Running' }],
components: {
securitySchemes: {
AuthJWT: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description:
'Enter a JSON Web Token (JWT) to be sent with each request in the HTTP **Authorization** header.',
},
},
},
security: [{ AuthJWT: [] }],
paths: {
'/dev/hello/echo': {
get: {
security: [],
summary: 'Responds with the request.',
description: '',
responses: { '200': { description: 'OK' } },
parameters: { q: 'string' }, // <-- THE INCORRECT BIT
tags: ['dev/hello'],
},
},
'/dev/hello/err': {
get: {
security: [],
summary: 'Responds with an error.',
description: '',
responses: { '500': { description: 'Error' } },
tags: ['dev/hello'],
},
},
},
tags: [{ name: 'dev/hello', description: 'API introduction' }],
};
}

0 comments on commit 9314b09

Please sign in to comment.