Skip to content

Commit

Permalink
docs: Fallback to reference description for responses (#826)
Browse files Browse the repository at this point in the history
* Fallback to reference description for responses

* Update lib/util/resolve-schema-reference.js

Signed-off-by: Gürgün Dayıoğlu <hey@gurgun.day>

* Adjust README entry to mention strict matching

* Update README.md

Co-authored-by: KaKa <23028015+climba03003@users.noreply.github.com>
Signed-off-by: Gürgün Dayıoğlu <hey@gurgun.day>

---------

Signed-off-by: Gürgün Dayıoğlu <hey@gurgun.day>
Co-authored-by: Gürgün Dayıoğlu <hey@gurgun.day>
Co-authored-by: KaKa <23028015+climba03003@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 11, 2024
1 parent 1de673f commit ac99039
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 2 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,9 @@ fastify.get('/responseDescription', {
}
}, () => {})
```
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.
<a name="route.response.2xx"></a>
##### Status code 2xx
Fastify supports both the `2xx` and `3xx` status codes, however Swagger (OpenAPI v2) itself does not.
Expand Down
11 changes: 10 additions & 1 deletion lib/spec/openapi/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const { readPackageJson } = require('../../util/read-package-json')
const { formatParamUrl } = require('../../util/format-param-url')
const { resolveLocalRef } = require('../../util/resolve-local-ref')
const { resolveSchemaReference } = require('../../util/resolve-schema-reference')
const { xResponseDescription, xConsume, xExamples } = require('../../constants')
const { rawRequired } = require('../../symbols')
const { generateParamsSchema } = require('../../util/generate-params-schema')
Expand Down Expand Up @@ -303,6 +304,11 @@ function resolveCommonParams (container, parameters, schema, ref, sharedSchemas,
arr.forEach(swaggerSchema => parameters.push(swaggerSchema))
}

function findReferenceDescription (rawSchema, ref) {
const resolved = resolveSchemaReference(rawSchema, ref)
return resolved?.description
}

// https://swagger.io/docs/specification/describing-responses/
function resolveResponse (fastifyResponseJson, produces, ref) {
// if the user does not provided an out schema
Expand All @@ -327,7 +333,10 @@ function resolveResponse (fastifyResponseJson, produces, ref) {
}

const response = {
description: resolved[xResponseDescription] || rawJsonSchema.description || 'Default Response'
description: resolved[xResponseDescription] ||
rawJsonSchema.description ||
findReferenceDescription(rawJsonSchema, ref) ||
'Default Response'
}

// add headers when there are any.
Expand Down
11 changes: 10 additions & 1 deletion lib/spec/swagger/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const { readPackageJson } = require('../../util/read-package-json')
const { formatParamUrl } = require('../../util/format-param-url')
const { resolveLocalRef } = require('../../util/resolve-local-ref')
const { resolveSchemaReference } = require('../../util/resolve-schema-reference')
const { xResponseDescription, xConsume } = require('../../constants')
const { generateParamsSchema } = require('../../util/generate-params-schema')
const { hasParams } = require('../../util/match-params')
Expand Down Expand Up @@ -205,6 +206,11 @@ function resolveCommonParams (container, parameters, schema, ref, sharedSchemas,
arr.forEach(swaggerSchema => parameters.push(swaggerSchema))
}

function findReferenceDescription (rawSchema, ref) {
const resolved = resolveSchemaReference(rawSchema, ref)
return resolved?.description
}

// https://swagger.io/docs/specification/2-0/describing-responses/
function resolveResponse (fastifyResponseJson, ref) {
// if the user does not provided an out schema
Expand Down Expand Up @@ -235,7 +241,10 @@ function resolveResponse (fastifyResponseJson, ref) {
}

const response = {
description: rawJsonSchema[xResponseDescription] || rawJsonSchema.description || 'Default Response'
description: rawJsonSchema[xResponseDescription] ||
rawJsonSchema.description ||
findReferenceDescription(rawJsonSchema, ref) ||
'Default Response'
}

// add headers when there are any.
Expand Down
18 changes: 18 additions & 0 deletions lib/util/resolve-schema-reference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

function resolveSchemaReference (rawSchema, ref) {
const resolvedReference = ref.resolve(rawSchema, { externalSchemas: [ref.definitions().definitions] })

// Ref has format `#/definitions/id`
const schemaId = resolvedReference?.$ref?.split('/', 3)[2]

if (schemaId === undefined) {
return undefined
}

return resolvedReference.definitions[schemaId]
}

module.exports = {
resolveSchemaReference
}
35 changes: 35 additions & 0 deletions test/spec/openapi/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,41 @@ test('response: description and x-response-description', async () => {
t.equal(schemaObject.description, description)
t.equal(schemaObject.responseDescription, undefined)
})

test('retrieve the response description from its given $ref schema', async t => {
// Given a /description endpoint that also has a |description| field in its response referenced schema
const fastify = Fastify()
fastify.addSchema({
$id: 'my-ref',
description,
type: 'string'
})

await fastify.register(fastifySwagger, openapiOption)
fastify.get('/description', {
schema: {
response: {
200: {
$ref: 'my-ref#'
}
}
}
}, () => {})
await fastify.ready()

// When the Swagger schema is generated
const swaggerObject = fastify.swagger()
const api = await Swagger.validate(swaggerObject)

const responseObject = api.paths['/description'].get.responses['200']
t.ok(responseObject)
t.equal(responseObject.description, description)

const schemaObject = responseObject.content['application/json'].schema
t.ok(schemaObject)
t.equal(schemaObject.description, description)
t.equal(schemaObject.responseDescription, undefined)
})
})

test('support default=null', async t => {
Expand Down
30 changes: 30 additions & 0 deletions test/spec/swagger/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,36 @@ test('support response description', async t => {
t.same(definedPath.responses['200'].description, 'Response OK!')
})

test('support response description fallback to its $ref', async t => {
const opts = {
schema: {
response: {
200: {
$ref: 'my-ref#'
}
}
}
}

const fastify = Fastify()
fastify.addSchema({
$id: 'my-ref',
description: 'Response OK!',
type: 'string'
})

await fastify.register(fastifySwagger)
fastify.get('/', opts, () => {})

await fastify.ready()

const swaggerObject = fastify.swagger()
const api = await Swagger.validate(swaggerObject)

const definedPath = api.paths['/'].get
t.same(definedPath.responses['200'].description, 'Response OK!')
})

test('response default description', async t => {
const opts9 = {
schema: {
Expand Down

0 comments on commit ac99039

Please sign in to comment.