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

fix: merged schemas reference resolving #546

Merged
merged 2 commits into from
Sep 26, 2022

Conversation

ivan-tymoshenko
Copy link
Member

Fix #540

index.js Outdated
schemaId: location.schemaId,
jsonPointer: location.jsonPointer + '/' + key,
isValidated: location.isValidated
class Location {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you evaluate the URL class?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't get you.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL class has many convenient methods to calculate if the URL is absolute and relative and compose it.

Looking at this Location class, I have afraid that we are going to replicate the URL class in future.

So I wanted to point it out to reduce the burden you could face by developing it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think they are the same and URL is really slow.
The usage here only string concatenation.

type: 'object',
properties: {
validation: {
$ref: '#/definitions/ValidationFragment'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about an absolute ref like schema:app:foo#/definitions/hello?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they are working. This PR doesn't change anything for absolute refs. The problem was that when we create merged schema we should have two locations to resolve local refs:

  1. We need location inside new "merged" schema in case if we have anyof/oneof .., inside merged schema.
  2. We original location to be able to resolve local reference in this schema, but outside of merged schema.

It's hard to explain simply) #480 Fixed the first case, but broke the second. This PR should support both.

index.js Outdated
schemaId: location.schemaId,
jsonPointer: location.jsonPointer + '/' + key,
isValidated: location.isValidated
class Location {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL class has many convenient methods to calculate if the URL is absolute and relative and compose it.

Looking at this Location class, I have afraid that we are going to replicate the URL class in future.

So I wanted to point it out to reduce the burden you could face by developing it

@ivan-tymoshenko ivan-tymoshenko force-pushed the fix-merged-schemas-reference-resolving branch from 3297481 to 034d32e Compare September 18, 2022 14:52
@ivan-tymoshenko
Copy link
Member Author

ivan-tymoshenko commented Sep 18, 2022

@Eomm I can't replace the hole Location class with an URL, we've got some custom logic here. I can use URL instead of split/join for schemaId and jsonPointer, but I'm not sure that it's a good idea. All the operations we have are quite simple and the URL is very slow in comparison.

index.js Outdated

this.isMerged = false
this.mergedSchemaId = null
this.mergedJsonPointer = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is currently hard to follow why does it fix the issue and how it is fixed.
Would you mind to add some comment of step flow why it works? and how the usage of mergedJsonPointer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@climba03003 @Eomm I will explain with an example. Sorry, it is not simple because the problem is not simple.

{
  $id: 'root',
  type: 'object',
  properties: {
    property1: { type: 'string' },
    property2: {
      type: 'object',
      allOf: [
        {
          properties: {
            property21: { $ref: '#/properties/property1' }
          }
        },
        {
          properties: {
            property22: {
              anyOf: [
                { type: 'string' },
                { type: 'number' }
              ]
            }
          }
        }
      ]
    }
  }
}
  1. When we meet property allOf, we create a merged schema and create a new unique id for it.

    mergedSchema.$id = `merged_${randomUUID()}`

    If we meet anyOf/oneOf/if inside the merged schema, we create a reference using the merged schema id.
    property22 will have the next reference: merged_12...223#/properties/property22. To create this reference, we should know the merged schema id.

  2. If somewhere inside the allOf schemas we meet a local reference like '#/properties/property1' we have to resolve it. To do this, we should know the original schema reference, which is root in this case.

So that is why we need to keep two schemas ids when we build a serializer inside the allOf property.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Location class now has two methods for getting schema id.

  1. getSchemaId - you should use it when you want to CREATE a new reference to some place in the schema. For example, for validation.
  2. getOriginSchemaId - you should use it when you want to RESOLVE a reference that already exists.

I added corresponding comments in the code.

index.js Outdated
addMergedSchema (schemaId, jsonPointer = '#') {
this.isMerged = true
this.mergedSchemaId = schemaId
this.mergedJsonPointer = jsonPointer
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this class into its own file under lib?

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
Copy link
Member

@Eomm @climba03003 @Uzlopak PTAL

Copy link
Member

@climba03003 climba03003 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
Thanks for the explanation, it's now more clear to me.

@mcollina mcollina merged commit f3b4183 into master Sep 26, 2022
@mcollina mcollina deleted the fix-merged-schemas-reference-resolving branch September 26, 2022 08:41
@remidewitte
Copy link
Contributor

Thanks. I will test asap :)

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

Successfully merging this pull request may close these issues.

Cannot find reference with allOf
5 participants