Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rendering the syntax of different content types responses #665

Merged
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<a name="route.response.empty_body"></a>
##### 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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Please use `content` for the response otherwise Fastify itself will fail to compile the schema:
Use `content` for the response otherwise Fastify itself will fail to compile the schema:

Nothing to please here ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please is used everywhere in the readme

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind removing it though


```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:
Expand Down
25 changes: 15 additions & 10 deletions lib/spec/openapi/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Uzlopak marked this conversation as resolved.
Show resolved Hide resolved

response.content = content
}
}

responsesContainer[statusCode] = response
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Uzlopak marked this conversation as resolved.
Show resolved Hide resolved
"fluent-json-schema": "^3.1.0",
"joi": "^17.6.0",
"joi-to-json": "^2.2.4",
Expand Down
90 changes: 90 additions & 0 deletions test/spec/openapi/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
iifawzi marked this conversation as resolved.
Show resolved Hide resolved
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: {
Expand Down