diff --git a/lib/spec/swagger/utils.js b/lib/spec/swagger/utils.js index 808c7c1d..1b0a55c0 100644 --- a/lib/spec/swagger/utils.js +++ b/lib/spec/swagger/utils.js @@ -155,6 +155,25 @@ function plainJsonObjectToSwagger2 (container, jsonSchema, externalSchemas, secu }) } +/* +* Map unsupported JSON schema definitions to Swagger definitions +*/ +function replaceUnsupported (jsonSchema) { + if (typeof jsonSchema === 'object' && jsonSchema !== null) { + // Handle patternProperties, that is not part of OpenAPI definitions + if (jsonSchema.patternProperties) { + jsonSchema.additionalProperties = { type: 'string' } + delete jsonSchema.patternProperties + } + + Object.keys(jsonSchema).forEach(function (key) { + jsonSchema[key] = replaceUnsupported(jsonSchema[key]) + }) + } + + return jsonSchema +} + function isConsumesFormOnly (schema) { const consumes = schema.consumes return ( @@ -168,6 +187,8 @@ function isConsumesFormOnly (schema) { function resolveBodyParams (parameters, schema, ref) { const resolved = ref.resolve(schema) + replaceUnsupported(resolved) + parameters.push({ name: 'body', in: 'body', @@ -224,6 +245,7 @@ function resolveResponse (fastifyResponseJson, ref) { // add schema when type is not 'null' if (rawJsonSchema.type !== 'null') { const schema = { ...resolved } + replaceUnsupported(schema) delete schema[xResponseDescription] response.schema = schema } diff --git a/test/spec/swagger/schema.js b/test/spec/swagger/schema.js index bb9f5486..d4a9fae1 100644 --- a/test/spec/swagger/schema.js +++ b/test/spec/swagger/schema.js @@ -415,3 +415,69 @@ test('fluent-json-schema', async t => { const definedPath = api.paths['/'].get t.same(definedPath.responses['200'].description, 'Default Response') }) + +test('support "patternProperties" in json schema', async t => { + const opt = { + schema: { + body: { + type: 'object', + patternProperties: { + '^[a-z]{2,3}-[a-zA-Z]{2}$': { + type: 'string' + } + } + }, + response: { + 200: { + description: 'Expected Response', + type: 'object', + properties: { + foo: { + type: 'object', + patternProperties: { + '^[a-z]{2,3}-[a-zA-Z]{2}$': { + type: 'string' + } + }, + additionalProperties: false + } + } + } + } + } + } + + const fastify = Fastify() + fastify.register(fastifySwagger, { + swagger: true, + routePrefix: '/docs', + exposeRoute: true + }) + fastify.get('/', opt, () => {}) + + await fastify.ready() + + const swaggerObject = fastify.swagger() + const api = await Swagger.validate(swaggerObject) + + const definedPath = api.paths['/'].get + + t.same(definedPath.parameters[0].schema, { + type: 'object', + additionalProperties: { type: 'string' } + }) + + t.same(definedPath.responses[200], { + description: 'Expected Response', + schema: { + description: 'Expected Response', + type: 'object', + properties: { + foo: { + type: 'object', + additionalProperties: { type: 'string' } + } + } + } + }) +})