diff --git a/README.md b/README.md index 8635959a..cc5cbc3f 100644 --- a/README.md +++ b/README.md @@ -431,6 +431,35 @@ 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 +**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: + +```js +{ + response: { + 200: { + description: 'Description and all status-code based properties are working', + content: { + 'application/json': { + schema: { + name: { type: 'string' }, + image: { type: 'string' }, + address: { type: 'string' } + } + }, + '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..8242d402 100644 --- a/lib/spec/openapi/utils.js +++ b/lib/spec/openapi/utils.js @@ -323,20 +323,25 @@ function resolveResponse (fastifyResponseJson, produces, ref) { // add schema when type is not 'null' if (rawJsonSchema.type !== 'null') { - const content = {} + if (resolved.content && resolved.content[Object.keys(resolved.content)[0]].schema) { + response.content = resolved.content + } else { + const content = {} - if ((Array.isArray(produces) && produces.length === 0) || typeof produces === 'undefined') { - produces = ['application/json'] - } + if ((Array.isArray(produces) && produces.length === 0) || typeof produces === 'undefined') { + produces = ['application/json'] + } - delete resolved[xResponseDescription] + delete resolved[xResponseDescription] - const media = schemaToMedia(resolved) - produces.forEach((produce) => { - content[produce] = media - }) + const media = schemaToMedia(resolved) - response.content = content + for (const produce of produces) { + content[produce] = media + } + + response.content = content + } } responsesContainer[statusCode] = response diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js index 0912071e..fae7b288 100644 --- a/test/spec/openapi/schema.js +++ b/test/spec/openapi/schema.js @@ -108,6 +108,96 @@ test('support 2xx response', async t => { t.same(definedPath.responses['3XX'].description, 'Default Response') }) +test('support multiple content types as response', 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', + content: { + 'application/json': { + schema: { + name: { type: 'string' }, + image: { type: 'string' }, + address: { type: 'string' } + } + }, + 'application/vnd.v1+json': { + schema: { + fullName: { type: 'string' }, + phone: { type: 'string' } + } + } + } + }, + '4xx': { + type: 'object', + properties: { + name: { type: 'string' } + } + }, + 300: { + age: { type: 'number' } + } + } + } + } + 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.strictSame(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' } + } + } + } + }) + t.same(definedPath.responses['4XX'].description, 'Default Response') + t.strictSame(definedPath.responses['4XX'].content, { + 'application/json': { + schema: { + type: 'object', + properties: { + name: { type: 'string' } + } + } + } + }) + t.strictSame(definedPath.responses[300].content, { + 'application/json': { + schema: { + type: 'object', + properties: { + age: { type: 'number' } + } + } + } + }) +}) + test('support status code 204', async t => { const opt = { schema: {