From 98de6807ec3deca0cad0ed42d2646668ce77eb6a Mon Sep 17 00:00:00 2001 From: lyndoh <20314316+lyndoh@users.noreply.github.com> Date: Mon, 3 May 2021 11:16:16 +1000 Subject: [PATCH] Throw error if spec specifies no content but actual response includes content/body (#591) Co-authored-by: Lyndon Howie --- src/middlewares/openapi.response.validator.ts | 16 ++++++++++++++++ test/response.validation.spec.ts | 14 +++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/middlewares/openapi.response.validator.ts b/src/middlewares/openapi.response.validator.ts index 91fcbc45..28494375 100644 --- a/src/middlewares/openapi.response.validator.ts +++ b/src/middlewares/openapi.response.validator.ts @@ -144,6 +144,19 @@ export class ResponseValidator { findResponseContent(accepts, validatorContentTypes) || validatorContentTypes[0]; // take first contentType, if none found + if (validatorContentTypes.length === 0) { + // spec specifies no content for this response + if (body !== undefined) { + // response contains content/body + throw new InternalServerError({ + path: '.response', + message: 'response should NOT have a body', + }); + } + // response contains no content/body so OK + return; + } + if (!contentType) { // not contentType inferred, assume valid console.warn('no contentType found'); @@ -275,6 +288,9 @@ export class ResponseValidator { const validators = {}; for (const [code, contentTypeSchemas] of Object.entries(responseSchemas)) { + if (Object.keys(contentTypeSchemas).length === 0) { + validators[code] = {}; + } for (const contentType of Object.keys(contentTypeSchemas)) { const schema = contentTypeSchemas[contentType]; schema.paths = this.spec.paths; // add paths for resolution with multi-file diff --git a/test/response.validation.spec.ts b/test/response.validation.spec.ts index 0cd03cb1..35c5241e 100644 --- a/test/response.validation.spec.ts +++ b/test/response.validation.spec.ts @@ -29,7 +29,10 @@ describe(packageJson.name, () => { return res.json({ id: 213, name: 'name', kids: [] }); }); app.get(`${app.basePath}/empty_response`, (req, res) => { - return res.status(204).send(); + if (req.query.mode === 'non_empty_response') { + return res.status(204).json({}); + } + return res.status(204).json(); }); app.get(`${app.basePath}/boolean`, (req, res) => { return res.json(req.query.value); @@ -175,6 +178,15 @@ describe(packageJson.name, () => { expect(r.body).to.be.empty; })); + it('should fail if response is not empty and an empty response is expected', async () => + request(app) + .get(`${app.basePath}/empty_response?mode=non_empty_response`) + .expect(500) + .then((r) => { + expect(r.body.message).to.contain('response should NOT have a body'); + expect(r.body).to.have.property('code').that.equals(500); + })); + it('should fail if additional properties are provided when set false', async () => request(app) .post(`${app.basePath}/no_additional_props`)