Skip to content

Commit ac99039

Browse files
Nelspikegurgundayclimba03003
authored
docs: Fallback to reference description for responses (#826)
* Fallback to reference description for responses * Update lib/util/resolve-schema-reference.js Signed-off-by: Gürgün Dayıoğlu <[email protected]> * Adjust README entry to mention strict matching * Update README.md Co-authored-by: KaKa <[email protected]> Signed-off-by: Gürgün Dayıoğlu <[email protected]> --------- Signed-off-by: Gürgün Dayıoğlu <[email protected]> Co-authored-by: Gürgün Dayıoğlu <[email protected]> Co-authored-by: KaKa <[email protected]>
1 parent 1de673f commit ac99039

File tree

6 files changed

+106
-2
lines changed

6 files changed

+106
-2
lines changed

Diff for: README.md

+3
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,9 @@ fastify.get('/responseDescription', {
468468
}
469469
}, () => {})
470470
```
471+
472+
Additionally, if you provide a `$ref` in your response schema but no description, the reference's description will be used as a fallback. Note that at the moment, `$ref` will only be resolved by matching with `$id` and not through complex paths.
473+
471474
<a name="route.response.2xx"></a>
472475
##### Status code 2xx
473476
Fastify supports both the `2xx` and `3xx` status codes, however Swagger (OpenAPI v2) itself does not.

Diff for: lib/spec/openapi/utils.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const { readPackageJson } = require('../../util/read-package-json')
44
const { formatParamUrl } = require('../../util/format-param-url')
55
const { resolveLocalRef } = require('../../util/resolve-local-ref')
6+
const { resolveSchemaReference } = require('../../util/resolve-schema-reference')
67
const { xResponseDescription, xConsume, xExamples } = require('../../constants')
78
const { rawRequired } = require('../../symbols')
89
const { generateParamsSchema } = require('../../util/generate-params-schema')
@@ -303,6 +304,11 @@ function resolveCommonParams (container, parameters, schema, ref, sharedSchemas,
303304
arr.forEach(swaggerSchema => parameters.push(swaggerSchema))
304305
}
305306

307+
function findReferenceDescription (rawSchema, ref) {
308+
const resolved = resolveSchemaReference(rawSchema, ref)
309+
return resolved?.description
310+
}
311+
306312
// https://swagger.io/docs/specification/describing-responses/
307313
function resolveResponse (fastifyResponseJson, produces, ref) {
308314
// if the user does not provided an out schema
@@ -327,7 +333,10 @@ function resolveResponse (fastifyResponseJson, produces, ref) {
327333
}
328334

329335
const response = {
330-
description: resolved[xResponseDescription] || rawJsonSchema.description || 'Default Response'
336+
description: resolved[xResponseDescription] ||
337+
rawJsonSchema.description ||
338+
findReferenceDescription(rawJsonSchema, ref) ||
339+
'Default Response'
331340
}
332341

333342
// add headers when there are any.

Diff for: lib/spec/swagger/utils.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const { readPackageJson } = require('../../util/read-package-json')
44
const { formatParamUrl } = require('../../util/format-param-url')
55
const { resolveLocalRef } = require('../../util/resolve-local-ref')
6+
const { resolveSchemaReference } = require('../../util/resolve-schema-reference')
67
const { xResponseDescription, xConsume } = require('../../constants')
78
const { generateParamsSchema } = require('../../util/generate-params-schema')
89
const { hasParams } = require('../../util/match-params')
@@ -205,6 +206,11 @@ function resolveCommonParams (container, parameters, schema, ref, sharedSchemas,
205206
arr.forEach(swaggerSchema => parameters.push(swaggerSchema))
206207
}
207208

209+
function findReferenceDescription (rawSchema, ref) {
210+
const resolved = resolveSchemaReference(rawSchema, ref)
211+
return resolved?.description
212+
}
213+
208214
// https://swagger.io/docs/specification/2-0/describing-responses/
209215
function resolveResponse (fastifyResponseJson, ref) {
210216
// if the user does not provided an out schema
@@ -235,7 +241,10 @@ function resolveResponse (fastifyResponseJson, ref) {
235241
}
236242

237243
const response = {
238-
description: rawJsonSchema[xResponseDescription] || rawJsonSchema.description || 'Default Response'
244+
description: rawJsonSchema[xResponseDescription] ||
245+
rawJsonSchema.description ||
246+
findReferenceDescription(rawJsonSchema, ref) ||
247+
'Default Response'
239248
}
240249

241250
// add headers when there are any.

Diff for: lib/util/resolve-schema-reference.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict'
2+
3+
function resolveSchemaReference (rawSchema, ref) {
4+
const resolvedReference = ref.resolve(rawSchema, { externalSchemas: [ref.definitions().definitions] })
5+
6+
// Ref has format `#/definitions/id`
7+
const schemaId = resolvedReference?.$ref?.split('/', 3)[2]
8+
9+
if (schemaId === undefined) {
10+
return undefined
11+
}
12+
13+
return resolvedReference.definitions[schemaId]
14+
}
15+
16+
module.exports = {
17+
resolveSchemaReference
18+
}

Diff for: test/spec/openapi/schema.js

+35
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,41 @@ test('response: description and x-response-description', async () => {
387387
t.equal(schemaObject.description, description)
388388
t.equal(schemaObject.responseDescription, undefined)
389389
})
390+
391+
test('retrieve the response description from its given $ref schema', async t => {
392+
// Given a /description endpoint that also has a |description| field in its response referenced schema
393+
const fastify = Fastify()
394+
fastify.addSchema({
395+
$id: 'my-ref',
396+
description,
397+
type: 'string'
398+
})
399+
400+
await fastify.register(fastifySwagger, openapiOption)
401+
fastify.get('/description', {
402+
schema: {
403+
response: {
404+
200: {
405+
$ref: 'my-ref#'
406+
}
407+
}
408+
}
409+
}, () => {})
410+
await fastify.ready()
411+
412+
// When the Swagger schema is generated
413+
const swaggerObject = fastify.swagger()
414+
const api = await Swagger.validate(swaggerObject)
415+
416+
const responseObject = api.paths['/description'].get.responses['200']
417+
t.ok(responseObject)
418+
t.equal(responseObject.description, description)
419+
420+
const schemaObject = responseObject.content['application/json'].schema
421+
t.ok(schemaObject)
422+
t.equal(schemaObject.description, description)
423+
t.equal(schemaObject.responseDescription, undefined)
424+
})
390425
})
391426

392427
test('support default=null', async t => {

Diff for: test/spec/swagger/schema.js

+30
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,36 @@ test('support response description', async t => {
6969
t.same(definedPath.responses['200'].description, 'Response OK!')
7070
})
7171

72+
test('support response description fallback to its $ref', async t => {
73+
const opts = {
74+
schema: {
75+
response: {
76+
200: {
77+
$ref: 'my-ref#'
78+
}
79+
}
80+
}
81+
}
82+
83+
const fastify = Fastify()
84+
fastify.addSchema({
85+
$id: 'my-ref',
86+
description: 'Response OK!',
87+
type: 'string'
88+
})
89+
90+
await fastify.register(fastifySwagger)
91+
fastify.get('/', opts, () => {})
92+
93+
await fastify.ready()
94+
95+
const swaggerObject = fastify.swagger()
96+
const api = await Swagger.validate(swaggerObject)
97+
98+
const definedPath = api.paths['/'].get
99+
t.same(definedPath.responses['200'].description, 'Response OK!')
100+
})
101+
72102
test('response default description', async t => {
73103
const opts9 = {
74104
schema: {

0 commit comments

Comments
 (0)