Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot find reference with allOf #540

Closed
2 tasks done
remidewitte opened this issue Sep 13, 2022 · 3 comments · Fixed by #546
Closed
2 tasks done

Cannot find reference with allOf #540

remidewitte opened this issue Sep 13, 2022 · 3 comments · Fixed by #546
Labels
bug Confirmed bug

Comments

@remidewitte
Copy link
Contributor

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.5.3

Plugin version

5.3.0

Node.js version

16

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

12.2

Description

I suspect it comes from fastify/fastify#4049 shipped with fastify 4.2.0 but I cannot figure what is wrong with my case.
It used to work with fastify 4.1.0 .

Maybe you have a clue.

Steps to Reproduce

Schema is :

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "Test",
  "definitions": {
    "Problem": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": true,
      "properties": {
        "type": {
          "type": "string"
        }
      }
    },
    "ValidationFragment": {
      "type": "string"
    },
    "ValidationErrorProblem": {
      "type": "object",
      "allOf": [
        {
          "$ref": "#/definitions/Problem"
        },
        {
          "type": "object",
          "properties": {
            "validation": {
              "$ref": "#/definitions/ValidationFragment"
            }
          }
        }
      ]
    }
  },
  "additionalProperties": false,
  "type": "object"
}

Code is

import fastify from 'fastify';

const server = fastify();

const schema = require('./schema.json');
server.addSchema(schema);

server.post<{
}>(
  '/dummy',
  {
    schema: {
      response: {
        '400': {$ref: 'Test#/definitions/ValidationErrorProblem'},
      },
    }
  },
  async (_request, _reply) => {
    return 'OK'
  });

server.ready();

Error is :

node_modules/fastify/lib/route.js:326
              throw new FST_ERR_SCH_SERIALIZATION_BUILD(opts.method, url, error.message)
                    ^
FastifyError [Error]: Failed building the serialization schema for POST: /dummy, due to error Cannot find reference "#/definitions/ValidationFragment"

Expected Behavior

It used to work with fastify 4.1.0. I would expect FJS to compile the schema.

@climba03003
Copy link
Member

climba03003 commented Sep 13, 2022

The problem exist because of how allOf schema merged.

function mergeAllOfSchema (location, schema, mergedSchema) {
const allOfLocation = mergeLocation(location, 'allOf')
for (let i = 0; i < schema.allOf.length; i++) {
let allOfSchema = schema.allOf[i]
if (allOfSchema.$ref) {
const allOfSchemaLocation = mergeLocation(allOfLocation, i)
allOfSchema = resolveRef(allOfSchemaLocation, allOfSchema.$ref).schema
}
let allOfSchemaType = allOfSchema.type
if (allOfSchemaType === undefined) {
allOfSchemaType = inferTypeByKeyword(allOfSchema)
}
if (allOfSchemaType !== undefined) {
if (
mergedSchema.type !== undefined &&
mergedSchema.type !== allOfSchemaType
) {
throw new Error('allOf schemas have different type values')
}
mergedSchema.type = allOfSchemaType
}
if (allOfSchema.format !== undefined) {
if (
mergedSchema.format !== undefined &&
mergedSchema.format !== allOfSchema.format
) {
throw new Error('allOf schemas have different format values')
}
mergedSchema.format = allOfSchema.format
}
if (allOfSchema.nullable !== undefined) {
if (
mergedSchema.nullable !== undefined &&
mergedSchema.nullable !== allOfSchema.nullable
) {
throw new Error('allOf schemas have different nullable values')
}
mergedSchema.nullable = allOfSchema.nullable
}
if (allOfSchema.properties !== undefined) {
if (mergedSchema.properties === undefined) {
mergedSchema.properties = {}
}
Object.assign(mergedSchema.properties, allOfSchema.properties)
}
if (allOfSchema.additionalProperties !== undefined) {
if (mergedSchema.additionalProperties === undefined) {
mergedSchema.additionalProperties = {}
}
Object.assign(mergedSchema.additionalProperties, allOfSchema.additionalProperties)
}
if (allOfSchema.patternProperties !== undefined) {
if (mergedSchema.patternProperties === undefined) {
mergedSchema.patternProperties = {}
}
Object.assign(mergedSchema.patternProperties, allOfSchema.patternProperties)
}
if (allOfSchema.required !== undefined) {
if (mergedSchema.required === undefined) {
mergedSchema.required = []
}
mergedSchema.required.push(...allOfSchema.required)
}
if (allOfSchema.oneOf !== undefined) {
if (mergedSchema.oneOf === undefined) {
mergedSchema.oneOf = []
}
mergedSchema.oneOf.push(...allOfSchema.oneOf)
}
if (allOfSchema.anyOf !== undefined) {
if (mergedSchema.anyOf === undefined) {
mergedSchema.anyOf = []
}
mergedSchema.anyOf.push(...allOfSchema.anyOf)
}
if (allOfSchema.allOf !== undefined) {
mergeAllOfSchema(location, allOfSchema, mergedSchema)
}
}
delete mergedSchema.allOf
mergedSchema.$id = `merged_${randomUUID()}`
mergeAllOfSchemas[mergedSchema.$id] = mergedSchema
refResolver.addSchema(mergedSchema)
location.schemaId = mergedSchema.$id
location.jsonPointer = '#'
}

I don't think it can be fixed in a short time, the problem here lead to a complicated use-case.
And it may even leads to a deep / infinite loop since it requires to find every reference inside the schema.

cc @ivan-tymoshenko Do you have a time to investigate this issue?

@climba03003 climba03003 added the bug Confirmed bug label Sep 13, 2022
@climba03003
Copy link
Member

climba03003 commented Sep 13, 2022

As a workaround, I suggest you to change the schema as follow.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "Test",
  "definitions": {
    "Problem": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": true,
      "properties": {
        "type": {
          "type": "string"
        }
      }
    },
    "ValidationFragment": {
      "type": "string"
    },
    "ValidationErrorProblem": {
      "type": "object",
      "allOf": [
        {
          "$ref": "#/definitions/Problem"
        },
        {
          "type": "object",
          "properties": {
            "validation": {
              // all nested schema reference by $id
              "$ref": "Test#/definitions/ValidationFragment"
            }
          }
        }
      ]
    }
  },
  "additionalProperties": false,
  "type": "object"
}

@remidewitte
Copy link
Contributor Author

Thanks a lot for your quick answer and the workaround !
Let me know how I can help further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Confirmed bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants