Skip to content

Commit

Permalink
wip: support definitions from json-schema
Browse files Browse the repository at this point in the history
  • Loading branch information
asc11cat committed Oct 7, 2022
1 parent d8a57a4 commit 9c63e1b
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 8 deletions.
37 changes: 29 additions & 8 deletions lib/spec/openapi/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ function transformDefsToComponents (jsonSchema) {
jsonSchema[key][prop] = transformDefsToComponents(jsonSchema[key][prop])
})
} else if (key === '$ref') {
// replace the top-lvl path
jsonSchema[key] = jsonSchema[key].replace('definitions', 'components/schemas')
// replace the path for nested defs
jsonSchema[key] = jsonSchema[key].replaceAll('definitions', 'properties')
} else if (key === 'examples' && Array.isArray(jsonSchema[key]) && (jsonSchema[key].length > 1)) {
jsonSchema.examples = convertExamplesArrayToObject(jsonSchema.examples)
} else if (key === 'examples' && Array.isArray(jsonSchema[key]) && (jsonSchema[key].length === 1)) {
Expand Down Expand Up @@ -402,16 +405,34 @@ function prepareOpenapiSchemas (schemas, ref) {
return Object.entries(schemas)
.reduce((res, [name, schema]) => {
const _ = { ...schema }
const resolved = transformDefsToComponents(ref.resolve(_, { externalSchemas: [schemas] }))

// Swagger doesn't accept $id on /definitions schemas.
// The $ids are needed by Ref() to check the URI so we need
// to remove them at the end of the process
// definitions are added by resolve but they are replace by components.schemas
delete resolved.$id
delete resolved.definitions
// 'definitions' keyword is not supported by openapi in schema item
// but we can receive it from json-schema input
if (_.definitions) {
_.properties = {
..._.properties,
..._.definitions
}
}

// ref.resolve call does 3 things:
// modifies underlying cache of ref
// adds 'definitions' with resolved schema(which we don't need here anymore)
// mutates $ref to point to the resolved schema
// ($ref will be mutated again by transformDefsToComponents)
const resolvedRef = ref.resolve(_, { externalSchemas: [schemas] })

// swagger doesn't accept $id on components schemas
// $ids are needed by ref.resolve to check the URI
// definitions are added by resolve, but they are not needed, as we resolve
// the $ref to already existing schemas in components.schemas using method below, not the definition ones
// therefore, we delete both $id and definitions at the end of the process
delete resolvedRef.$id
delete resolvedRef.definitions

const components = transformDefsToComponents(resolvedRef)

res[name] = resolved
res[name] = components
return res
}, {})
}
Expand Down
39 changes: 39 additions & 0 deletions test/spec/openapi/refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,42 @@ test('uses examples if has property required in body', async (t) => {
t.ok(schema.parameters)
t.same(schema.parameters[0].in, 'query')
})

test('support schema with definitions keyword and $ref inside', async (t) => {
const fastify = Fastify()

await fastify.register(fastifySwagger, openapiOption)
fastify.register(async (instance) => {
instance.addSchema({
$id: 'NestedSchema',
definitions: {
SchemaA: {
type: 'object',
properties: {
id: { type: 'string' }
}
},
SchemaB: {
type: 'object',
properties: {
example: { $ref: 'NestedSchema#/definitions/SchemaA' }
}
}
}
})
instance.post('/url1', { schema: { body: { $ref: 'NestedSchema#/definitions/SchemaB' }, response: { 200: { $ref: 'NestedSchema#/definitions/SchemaA' } } } }, () => {})
})

await fastify.ready()

const openapiObject = fastify.swagger()
t.equal(typeof openapiObject, 'object')
t.match(Object.keys(openapiObject.components.schemas), ['NestedSchema'])
t.match(Object.keys(openapiObject.components.schemas.NestedSchema), ['properties'])
t.match(Object.keys(openapiObject.components.schemas.NestedSchema.properties), ['SchemaA', 'SchemaB'])

// ref must be prefixed by '#/components/schemas/'
t.equal(openapiObject.components.schemas.NestedSchema.properties.SchemaB.properties.example.$ref, '#/components/schemas/NestedSchema/properties/SchemaA')

await Swagger.validate(openapiObject)
})

0 comments on commit 9c63e1b

Please sign in to comment.