Skip to content

Commit

Permalink
fix: keep custom response schema class (#4718)
Browse files Browse the repository at this point in the history
* add test and fix to maintain custom response schema

* ensure mixed schema types are individually skipped or normalized
  • Loading branch information
jaschaephraim committed May 1, 2023
1 parent fc09e73 commit af1e042
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 21 deletions.
39 changes: 18 additions & 21 deletions lib/schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ Schemas.prototype.getSchema = function (schemaId) {
return this.store[schemaId]
}

/**
* Checks whether a schema is a non-plain object.
*
* @param {*} schema the schema to check
* @returns {boolean} true if schema has a custom prototype
*/
function isCustomSchemaPrototype (schema) {
return typeof schema === 'object' && Object.getPrototypeOf(schema) !== Object.prototype
}

function normalizeSchema (routeSchemas, serverOptions) {
if (routeSchemas[kSchemaVisited]) {
return routeSchemas
Expand All @@ -60,33 +70,20 @@ function normalizeSchema (routeSchemas, serverOptions) {

generateFluentSchema(routeSchemas)

// let's check if our schemas have a custom prototype
for (const key of ['headers', 'querystring', 'params', 'body']) {
if (typeof routeSchemas[key] === 'object' && Object.getPrototypeOf(routeSchemas[key]) !== Object.prototype) {
routeSchemas[kSchemaVisited] = true
return routeSchemas
for (const key of SCHEMAS_SOURCE) {
const schema = routeSchemas[key]
if (schema && !isCustomSchemaPrototype(schema)) {
routeSchemas[key] = getSchemaAnyway(schema, serverOptions.jsonShorthand)
}
}

if (routeSchemas.body) {
routeSchemas.body = getSchemaAnyway(routeSchemas.body, serverOptions.jsonShorthand)
}

if (routeSchemas.headers) {
routeSchemas.headers = getSchemaAnyway(routeSchemas.headers, serverOptions.jsonShorthand)
}

if (routeSchemas.querystring) {
routeSchemas.querystring = getSchemaAnyway(routeSchemas.querystring, serverOptions.jsonShorthand)
}

if (routeSchemas.params) {
routeSchemas.params = getSchemaAnyway(routeSchemas.params, serverOptions.jsonShorthand)
}

if (routeSchemas.response) {
const httpCodes = Object.keys(routeSchemas.response)
for (const code of httpCodes) {
if (isCustomSchemaPrototype(routeSchemas.response[code])) {
continue
}

const contentProperty = routeSchemas.response[code].content

let hasContentMultipleContentTypes = false
Expand Down
58 changes: 58 additions & 0 deletions test/internals/validation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,61 @@ test('build schema - uppercased headers are not included', t => {
return () => {}
})
})

test('build schema - mixed schema types are individually skipped or normalized', t => {
t.plan(6)

class CustomSchemaClass {}
const nonNormalizedSchema = {
hello: { type: 'string' }
}
const normalizedSchema = {
type: 'object',
properties: nonNormalizedSchema
}

const testCases = [{
schema: {
body: new CustomSchemaClass()
},
assertions: (schema) => {
t.type(schema.body, CustomSchemaClass)
}
}, {
schema: {
response: {
200: new CustomSchemaClass()
}
},
assertions: (schema) => {
t.type(schema.response[200], CustomSchemaClass)
}
}, {
schema: {
body: nonNormalizedSchema,
response: {
200: new CustomSchemaClass()
}
},
assertions: (schema) => {
t.same(schema.body, normalizedSchema)
t.type(schema.response[200], CustomSchemaClass)
}
}, {
schema: {
body: new CustomSchemaClass(),
response: {
200: nonNormalizedSchema
}
},
assertions: (schema) => {
t.type(schema.body, CustomSchemaClass)
t.same(schema.response[200], normalizedSchema)
}
}]

testCases.forEach((testCase) => {
const result = normalizeSchema(testCase.schema, { jsonShorthand: true })
testCase.assertions(result)
})
})

0 comments on commit af1e042

Please sign in to comment.