From 3ee3233e4022e8c35c41ec1bf3c606e3d45af827 Mon Sep 17 00:00:00 2001 From: iifawzi Date: Sun, 11 Sep 2022 20:37:58 +0200 Subject: [PATCH 01/11] Supporting different content types responses Signed-off-by: iifawzi --- README.md | 23 ++++++++++++++++ lib/spec/openapi/utils.js | 30 ++++++++++++-------- test/spec/openapi/schema.js | 55 +++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6c33929b..9156a401 100644 --- a/README.md +++ b/README.md @@ -451,6 +451,29 @@ You can decorate your own response headers by following the below example: Note: You need to specify `type` property when you decorate the response headers, otherwise the schema will be modified by Fastify. +##### Different content types responses +Different content types responses are supported by `@fastify/swagger` and `@fastify`. +Please use `contentTypes` for the response otherwise Fastify itself will fail to compile the schema: + +```js +{ + response: { + 200: { + description: 'Description and all status-code based properties are working', + contentTypes: [ + { + content: 'application/json', + schema: { name: { type: 'string' }, image: { type: 'string' }, address: { type: 'string' } } + }, + { + content: 'application/vnd.v1+json', + schema: { fullName: { type: 'string' }, phone: { type: 'string' } } + } + ] + } + } +} +``` ##### Empty Body Responses Empty body responses are supported by `@fastify/swagger`. Please specify `type: 'null'` for the response otherwise Fastify itself will fail to compile the schema: diff --git a/lib/spec/openapi/utils.js b/lib/spec/openapi/utils.js index 5583022d..971f62af 100644 --- a/lib/spec/openapi/utils.js +++ b/lib/spec/openapi/utils.js @@ -323,20 +323,28 @@ function resolveResponse (fastifyResponseJson, produces, ref) { // add schema when type is not 'null' if (rawJsonSchema.type !== 'null') { - const content = {} - - if ((Array.isArray(produces) && produces.length === 0) || typeof produces === 'undefined') { - produces = ['application/json'] - } + if (Array.isArray(resolved.contentTypes)) { + const content = {} + for (const contnetTypeResponse of resolved.contentTypes) { + const media = schemaToMedia(contnetTypeResponse.schema) + content[contnetTypeResponse.content] = media + response.content = content + } + } else { + const content = {} - delete resolved[xResponseDescription] + if ((Array.isArray(produces) && produces.length === 0) || typeof produces === 'undefined') { + produces = ['application/json'] + } - const media = schemaToMedia(resolved) - produces.forEach((produce) => { - content[produce] = media - }) + delete resolved[xResponseDescription] - response.content = content + const media = schemaToMedia(resolved) + produces.forEach((produce) => { + content[produce] = media + }) + response.content = content + } } responsesContainer[statusCode] = response diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js index 10bc4e48..9c103530 100644 --- a/test/spec/openapi/schema.js +++ b/test/spec/openapi/schema.js @@ -110,6 +110,61 @@ test('support 2xx response', async t => { t.same(definedPath.responses['3XX'].description, 'Default Response') }) +test('support multiple content types responses', async t => { + const fastify = Fastify() + await fastify.register(fastifySwagger, { + openapi: true, + routePrefix: '/docs', + exposeRoute: true + }) + + const opt = { + schema: { + response: { + 200: { + description: 'Description and all status-code based properties are working', + contentTypes: [ + { + content: 'application/json', + schema: { name: { type: 'string' }, image: { type: 'string' }, address: { type: 'string' } } + }, + { + content: 'application/vnd.v1+json', + schema: { fullName: { type: 'string' }, phone: { type: 'string' } } + } + ] + } + } + } + } + fastify.get('/', opt, () => {}) + + await fastify.ready() + + const swaggerObject = fastify.swagger() + const api = await Swagger.validate(swaggerObject) + const definedPath = api.paths['/'].get + t.same(definedPath.responses['200'].description, 'Description and all status-code based properties are working') + t.same(definedPath.responses['200'].content, { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string' }, image: { type: 'string' }, address: { type: 'string' } + } + } + }, + 'application/vnd.v1+json': { + schema: { + type: 'object', + properties: { + fullName: { type: 'string' }, phone: { type: 'string' } + } + } + } + }) +}) + test('support status code 204', async t => { const opt = { schema: { From 452f55a682f096bcb8e9ebf9d7bffc82fd0cc267 Mon Sep 17 00:00:00 2001 From: iifawzi Date: Sun, 11 Sep 2022 21:10:02 +0200 Subject: [PATCH 02/11] updating the docs Signed-off-by: iifawzi --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9156a401..59bb1cfb 100644 --- a/README.md +++ b/README.md @@ -452,6 +452,9 @@ Note: You need to specify `type` property when you decorate the response headers ##### Different content types responses +**Note:** not supported by Swagger (OpenAPI v2), [only OpenAPI v3](https://swagger.io/docs/specification/describing-responses/) +
+
Different content types responses are supported by `@fastify/swagger` and `@fastify`. Please use `contentTypes` for the response otherwise Fastify itself will fail to compile the schema: From 315333156d4dac24d01e7e818df88c31ad6fc274 Mon Sep 17 00:00:00 2001 From: iifawzi Date: Mon, 12 Sep 2022 09:13:00 +0200 Subject: [PATCH 03/11] Refactoring for-loop and update the tests Signed-off-by: iifawzi --- lib/spec/openapi/utils.js | 6 ++++-- package.json | 1 + test/spec/openapi/schema.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/spec/openapi/utils.js b/lib/spec/openapi/utils.js index 971f62af..9ff20ddc 100644 --- a/lib/spec/openapi/utils.js +++ b/lib/spec/openapi/utils.js @@ -340,9 +340,11 @@ function resolveResponse (fastifyResponseJson, produces, ref) { delete resolved[xResponseDescription] const media = schemaToMedia(resolved) - produces.forEach((produce) => { + + for (const produce of produces) { content[produce] = media - }) + } + response.content = content } } diff --git a/package.json b/package.json index d8867b1b..1ed4d0ab 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "tsd": "^0.23.0" }, "dependencies": { + "fastify": "github:iifawzi/fastify#supporting-different-content-types", "@fastify/static": "^6.0.0", "fastify-plugin": "^4.0.0", "json-schema-resolver": "^1.3.0", diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js index 9c103530..0540bd34 100644 --- a/test/spec/openapi/schema.js +++ b/test/spec/openapi/schema.js @@ -133,6 +133,15 @@ test('support multiple content types responses', async t => { schema: { fullName: { type: 'string' }, phone: { type: 'string' } } } ] + }, + '4xx': { + type: 'object', + properties: { + name: { type: 'string' } + } + }, + 300: { + age: { type: 'number' } } } } @@ -163,6 +172,27 @@ test('support multiple content types responses', async t => { } } }) + t.same(definedPath.responses['4XX'].description, 'Default Response') + t.same(definedPath.responses['4XX'].content, { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string' } + } + } + } + }) + t.same(definedPath.responses[300].content, { + 'application/json': { + schema: { + type: 'object', + properties: { + age: { type: 'number' } + } + } + } + }) }) test('support status code 204', async t => { From cea4a9419b5d531e893938604d2e5b66be4a02ca Mon Sep 17 00:00:00 2001 From: iifawzi Date: Mon, 12 Sep 2022 09:30:56 +0200 Subject: [PATCH 04/11] update package.json to use repo Signed-off-by: iifawzi --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 1ed4d0ab..d4a9fda4 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "@fastify/helmet": "^10.0.0", "@fastify/pre-commit": "^2.0.2", "@types/node": "^18.0.0", - "fastify": "^4.0.0", "fluent-json-schema": "^3.1.0", "fs-extra": "^10.1.0", "joi": "^17.6.0", From e1a6931744ba961f48486d5f69d3f882e8c5ac1c Mon Sep 17 00:00:00 2001 From: iifawzi Date: Tue, 13 Sep 2022 11:32:03 +0200 Subject: [PATCH 05/11] update the rendering logic according to fastify changes Signed-off-by: iifawzi --- README.md | 25 +++++++++++++++---------- lib/spec/openapi/utils.js | 9 ++------- test/spec/openapi/schema.js | 21 +++++++++++++-------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 59bb1cfb..6a736b25 100644 --- a/README.md +++ b/README.md @@ -456,23 +456,28 @@ Note: You need to specify `type` property when you decorate the response headers

Different content types responses are supported by `@fastify/swagger` and `@fastify`. -Please use `contentTypes` for the response otherwise Fastify itself will fail to compile the schema: +Please use `content` for the response otherwise Fastify itself will fail to compile the schema: ```js { response: { 200: { description: 'Description and all status-code based properties are working', - contentTypes: [ - { - content: 'application/json', - schema: { name: { type: 'string' }, image: { type: 'string' }, address: { type: 'string' } } - }, - { - content: 'application/vnd.v1+json', - schema: { fullName: { type: 'string' }, phone: { type: 'string' } } + content: { + 'application/json': { + schema: { + name: { type: 'string' }, + image: { type: 'string' }, + address: { type: 'string' } + } + }, + 'application/vnd.v1+json': { + schema: { + fullName: { type: 'string' }, + phone: { type: 'string' } + } } - ] + } } } } diff --git a/lib/spec/openapi/utils.js b/lib/spec/openapi/utils.js index 9ff20ddc..f5de50af 100644 --- a/lib/spec/openapi/utils.js +++ b/lib/spec/openapi/utils.js @@ -323,13 +323,8 @@ function resolveResponse (fastifyResponseJson, produces, ref) { // add schema when type is not 'null' if (rawJsonSchema.type !== 'null') { - if (Array.isArray(resolved.contentTypes)) { - const content = {} - for (const contnetTypeResponse of resolved.contentTypes) { - const media = schemaToMedia(contnetTypeResponse.schema) - content[contnetTypeResponse.content] = media - response.content = content - } + if (resolved.content && !resolved.content.type) { + response.content = resolved.content } else { const content = {} diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js index 0540bd34..728f2d85 100644 --- a/test/spec/openapi/schema.js +++ b/test/spec/openapi/schema.js @@ -123,16 +123,21 @@ test('support multiple content types responses', async t => { response: { 200: { description: 'Description and all status-code based properties are working', - contentTypes: [ - { - content: 'application/json', - schema: { name: { type: 'string' }, image: { type: 'string' }, address: { type: 'string' } } + content: { + 'application/json': { + schema: { + name: { type: 'string' }, + image: { type: 'string' }, + address: { type: 'string' } + } }, - { - content: 'application/vnd.v1+json', - schema: { fullName: { type: 'string' }, phone: { type: 'string' } } + 'application/vnd.v1+json': { + schema: { + fullName: { type: 'string' }, + phone: { type: 'string' } + } } - ] + } }, '4xx': { type: 'object', From 6109b525c5dc7bcacbdeb57c496fbaeb4456cbee Mon Sep 17 00:00:00 2001 From: iifawzi Date: Fri, 30 Sep 2022 16:47:40 +0200 Subject: [PATCH 06/11] update the ducktyping Signed-off-by: iifawzi --- lib/spec/openapi/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spec/openapi/utils.js b/lib/spec/openapi/utils.js index f5de50af..8242d402 100644 --- a/lib/spec/openapi/utils.js +++ b/lib/spec/openapi/utils.js @@ -323,7 +323,7 @@ function resolveResponse (fastifyResponseJson, produces, ref) { // add schema when type is not 'null' if (rawJsonSchema.type !== 'null') { - if (resolved.content && !resolved.content.type) { + if (resolved.content && resolved.content[Object.keys(resolved.content)[0]].schema) { response.content = resolved.content } else { const content = {} From e41801347c06a818ce48b451fb0f31a521dc9d8b Mon Sep 17 00:00:00 2001 From: "Fawzi E. Abdulfattah" Date: Fri, 7 Oct 2022 13:40:19 +0200 Subject: [PATCH 07/11] Apply suggestions from code review Co-authored-by: Uzlopak --- README.md | 2 -- test/spec/openapi/schema.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 6a736b25..38439c4e 100644 --- a/README.md +++ b/README.md @@ -453,8 +453,6 @@ Note: You need to specify `type` property when you decorate the response headers ##### Different content types responses **Note:** not supported by Swagger (OpenAPI v2), [only OpenAPI v3](https://swagger.io/docs/specification/describing-responses/) -
-
Different content types responses are supported by `@fastify/swagger` and `@fastify`. Please use `content` for the response otherwise Fastify itself will fail to compile the schema: diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js index 728f2d85..8963c434 100644 --- a/test/spec/openapi/schema.js +++ b/test/spec/openapi/schema.js @@ -178,7 +178,7 @@ test('support multiple content types responses', async t => { } }) t.same(definedPath.responses['4XX'].description, 'Default Response') - t.same(definedPath.responses['4XX'].content, { + t.strictSame(definedPath.responses['4XX'].content, { 'application/json': { schema: { type: 'object', From dd9654a27d7921fb62f37d91d186c7a5f0205ed0 Mon Sep 17 00:00:00 2001 From: iifawzi Date: Fri, 14 Oct 2022 22:04:53 +0200 Subject: [PATCH 08/11] revert fastify deleted by mistake Signed-off-by: iifawzi --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a9a2d028..774f4cf2 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@apidevtools/swagger-parser": "^10.1.0", "@fastify/pre-commit": "^2.0.2", "@types/node": "^18.0.0", + "fastify": "^4.0.0", "fluent-json-schema": "^3.1.0", "joi": "^17.6.0", "joi-to-json": "^2.2.4", From 6294316c3af49b0ebcdc635b306df12bf04f4b20 Mon Sep 17 00:00:00 2001 From: "Fawzi E. Abdulfattah" Date: Sat, 15 Oct 2022 13:03:10 +0200 Subject: [PATCH 09/11] Update test/spec/openapi/schema.js Co-authored-by: Uzlopak --- test/spec/openapi/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js index 9491e02c..ffa44136 100644 --- a/test/spec/openapi/schema.js +++ b/test/spec/openapi/schema.js @@ -108,7 +108,7 @@ test('support 2xx response', async t => { t.same(definedPath.responses['3XX'].description, 'Default Response') }) -test('support multiple content types responses', async t => { +test('support multiple content types as response', async t => { const fastify = Fastify() await fastify.register(fastifySwagger, { openapi: true, From 54fcac6e3fcc0ccb15a8bc47bda84cd868290aa3 Mon Sep 17 00:00:00 2001 From: iifawzi Date: Sat, 15 Oct 2022 13:11:44 +0200 Subject: [PATCH 10/11] Using strictSame and temporary updat packagejson to check ci Signed-off-by: iifawzi --- package.json | 2 +- test/spec/openapi/schema.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 774f4cf2..b83df38d 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@apidevtools/swagger-parser": "^10.1.0", "@fastify/pre-commit": "^2.0.2", "@types/node": "^18.0.0", - "fastify": "^4.0.0", + "fastify": "github:fastify/fastify", "fluent-json-schema": "^3.1.0", "joi": "^17.6.0", "joi-to-json": "^2.2.4", diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js index ffa44136..fae7b288 100644 --- a/test/spec/openapi/schema.js +++ b/test/spec/openapi/schema.js @@ -157,7 +157,7 @@ test('support multiple content types as response', async t => { const api = await Swagger.validate(swaggerObject) const definedPath = api.paths['/'].get t.same(definedPath.responses['200'].description, 'Description and all status-code based properties are working') - t.same(definedPath.responses['200'].content, { + t.strictSame(definedPath.responses['200'].content, { 'application/json': { schema: { type: 'object', @@ -186,7 +186,7 @@ test('support multiple content types as response', async t => { } } }) - t.same(definedPath.responses[300].content, { + t.strictSame(definedPath.responses[300].content, { 'application/json': { schema: { type: 'object', From cdb95699652c9979d2eb05efc898c60b43f30eff Mon Sep 17 00:00:00 2001 From: iifawzi Date: Mon, 17 Oct 2022 10:02:36 +0200 Subject: [PATCH 11/11] update deps Signed-off-by: iifawzi --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b83df38d..774f4cf2 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@apidevtools/swagger-parser": "^10.1.0", "@fastify/pre-commit": "^2.0.2", "@types/node": "^18.0.0", - "fastify": "github:fastify/fastify", + "fastify": "^4.0.0", "fluent-json-schema": "^3.1.0", "joi": "^17.6.0", "joi-to-json": "^2.2.4",