Skip to content

Commit

Permalink
add option to ignore undocumented #577 (#637)
Browse files Browse the repository at this point in the history
  • Loading branch information
milo526 authored Aug 20, 2021
1 parent 356fb18 commit a760af6
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 3 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ OpenApiValidator.middleware({
],
operationHandlers: false | 'operations/base/path' | { ... },
ignorePaths: /.*\/pets$/,
ignoreUndocumented: false,
fileUploader: { ... } | true | false,
$refParser: {
mode: 'bundle'
Expand Down Expand Up @@ -875,6 +876,12 @@ or as a function:
ignorePaths: (path) => path.endsWith('/pets')
```

### ▪️ ignoreUndocumented (optional)

Disables any form of validation for requests which are not documented in the OpenAPI spec.

Defaults to `false`

### ▪️ fileUploader (optional)

Specifies the options to passthrough to multer. express-openapi-validator uses multer to handle file uploads. see [multer opts](https://github.com/expressjs/multer)
Expand Down
4 changes: 3 additions & 1 deletion src/framework/openapi.context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ export class OpenApiContext {
public readonly expressRouteMap = {};
public readonly openApiRouteMap = {};
public readonly routes: RouteMetadata[] = [];
public readonly ignoreUndocumented: boolean;
private readonly basePaths: string[];
private readonly ignorePaths: RegExp | Function;

constructor(spec: Spec, ignorePaths: RegExp | Function) {
constructor(spec: Spec, ignorePaths: RegExp | Function, ignoreUndocumented: boolean = false) {
this.apiDoc = spec.apiDoc;
this.basePaths = spec.basePaths;
this.routes = spec.routes;
this.ignorePaths = ignorePaths;
this.ignoreUndocumented = ignoreUndocumented;
this.buildRouteMaps(spec.routes);
}

Expand Down
1 change: 1 addition & 0 deletions src/framework/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export interface OpenApiValidatorOpts {
validateRequests?: boolean | ValidateRequestOpts;
validateSecurity?: boolean | ValidateSecurityOpts;
ignorePaths?: RegExp | Function;
ignoreUndocumented?: boolean;
securityHandlers?: SecurityHandlers;
coerceTypes?: boolean | 'array';
unknownFormats?: true | string[] | 'ignore';
Expand Down
6 changes: 5 additions & 1 deletion src/middlewares/openapi.metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export function applyOpenApiMetadata(
if (matched) {
const { expressRoute, openApiRoute, pathParams, schema } = matched;
if (!schema) {
// Prevents validation for routes which match on path but mismatch on method
if(openApiContext.ignoreUndocumented) {
return next();
}
throw new MethodNotAllowed({
path: req.path,
message: `${req.method} method not allowed`,
Expand All @@ -50,7 +54,7 @@ export function applyOpenApiMetadata(
// add the response schema if validating responses
(<any>req.openapi)._responseSchema = (<any>matched)._responseSchema;
}
} else if (openApiContext.isManagedRoute(path)) {
} else if (openApiContext.isManagedRoute(path) && !openApiContext.ignoreUndocumented) {
throw new NotFound({
path: req.path,
message: 'not found',
Expand Down
2 changes: 1 addition & 1 deletion src/openapi.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class OpenApiValidator {
resOpts,
).preProcess();
return {
context: new OpenApiContext(spec, this.options.ignorePaths),
context: new OpenApiContext(spec, this.options.ignorePaths, this.options.ignoreUndocumented),
responseApiDoc: sp.apiDocRes,
error: null,
};
Expand Down
71 changes: 71 additions & 0 deletions test/577.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as express from 'express';
import { Server } from 'http';
import * as request from 'supertest';
import * as OpenApiValidator from '../src';
import { OpenAPIV3 } from '../src/framework/types';
import { startServer } from './common/app.common';
import { deepStrictEqual } from 'assert';

describe('#577 - Exclude response validation that is not in api spec', () => {
it('does not validate responses which are not present in the spec', async () => {
const apiSpec = createApiSpec();

const app = await createApp(apiSpec);
await request(app).get('/users').expect(200, 'some users');
await request(app).post('/users').expect(201, 'Created!');
await request(app).get ('/example').expect(200, 'Example indeed')
app.server.close();

deepStrictEqual(apiSpec, createApiSpec());
});
});

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

app.use(
OpenApiValidator.middleware({
apiSpec,
validateRequests: true,
validateResponses: true,
ignoreUndocumented: true,
}),
);
app.get('/users', (req, res) => {
res.status(200).send('some users');
}
);
app.post('/users', (req, res) => {
res.status(201).send('Created!');
}
);

app.get('/example', (req, res) => {
res.status(200).send('Example indeed');
}
);

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

function createApiSpec(): OpenAPIV3.Document {
return {
openapi: '3.0.3',
info: {
title: 'Ping API',
version: '1.0.0',
},
paths: {
'/users': {
get: {
responses: {
'200': { description: 'pong!' },
},
},
},
},
};
}

0 comments on commit a760af6

Please sign in to comment.