diff --git a/src/middlewares/openapi.metadata.ts b/src/middlewares/openapi.metadata.ts index a547fb7d..0906ef8f 100644 --- a/src/middlewares/openapi.metadata.ts +++ b/src/middlewares/openapi.metadata.ts @@ -29,7 +29,7 @@ export function applyOpenApiMetadata( }; function lookupRoute(req: OpenApiRequest): OpenApiRequestMetadata { - const path = req.path; + const path = req.originalUrl.split("?")[0]; const method = req.method; const routeEntries = Object.entries(openApiContext.expressRouteMap); for (const [expressRoute, methods] of routeEntries) { diff --git a/test/common/app.ts b/test/common/app.ts index a9656251..8bd56c96 100644 --- a/test/common/app.ts +++ b/test/common/app.ts @@ -13,6 +13,7 @@ export async function createApp( port = 3000, customRoutes = app => {}, useRoutes = true, + apiRouter = undefined, ) { var app = express(); (app).basePath = '/v1'; @@ -25,7 +26,7 @@ export async function createApp( app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); - await new OpenApiValidator(opts).install(app); + await new OpenApiValidator(opts).install(apiRouter || app); if (useRoutes) { // register common routes diff --git a/test/nested.routes.spec.ts b/test/nested.routes.spec.ts new file mode 100644 index 00000000..9c386eb6 --- /dev/null +++ b/test/nested.routes.spec.ts @@ -0,0 +1,56 @@ +import * as path from 'path'; +import * as express from 'express'; +import { expect } from 'chai'; +import * as request from 'supertest'; +import { createApp } from './common/app'; +import * as packageJson from '../package.json'; +describe(packageJson.name, () => { + let app = null; + + before(async () => { + // Set up the express app + const apiSpec = path.join( + 'test', + 'resources', + 'nested.routes.yaml', + ); + const apiRoute = express.Router(), + nestedRoute = express.Router(); + app = await createApp({ + apiSpec, + validateRequests: true, + validateResponses: true, + }, + 3005, + app =>{ + app.use(`${app.basePath}`, apiRoute); + apiRoute.use('/api-path', nestedRoute); + nestedRoute.get('/pets', (_req, res) => { + const json = [ + { + name: 'test', + tag: 'tag' + } + ]; + return res.json(json); + }) + }, + true, + apiRoute + ); + }); + + after(() => { + app.server.close(); + }); + + it('should fail, because response does not satisfy schema', async () => + request(app) + .get(`${app.basePath}/api-path/pets?qparam=test`) + .send() + .expect(500) + .then((r: any) => { + const e = r.body; + expect(e.message).to.contain(".response[0] should have required property 'id'"); + })); +}); diff --git a/test/resources/nested.routes.yaml b/test/resources/nested.routes.yaml new file mode 100644 index 00000000..4e0450ca --- /dev/null +++ b/test/resources/nested.routes.yaml @@ -0,0 +1,72 @@ +openapi: '3.0.2' +info: + version: 1.0.0 + title: Nested Express Routes + description: Nested Express Routes Test + +servers: + - url: /v1/api-path + +paths: + /pets: + description: endpoints for pets + summary: endpoints for pets + get: + description: find pets + operationId: findPets + parameters: + - name: qparam + in: query + schema: + type: string + responses: + '200': + description: pet response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + +components: + schemas: + NewPet: + required: + - name + properties: + bought_at: + type: string + format: date-time + nullable: true + name: + type: string + nullable: true + tag: + type: string + + Pet: + allOf: + - $ref: '#/components/schemas/NewPet' + - required: + - id + properties: + id: + type: integer + format: int64 + Error: + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string \ No newline at end of file