hyperjump-io / json-schema-bundle

A tool for bundling JSON Schema documents
MIT License
14 stars 1 forks source link

Bundler usage and $ref pointers #1

Closed gavinbarron closed 2 years ago

gavinbarron commented 2 years ago

Hi!

I got pointed at your repo from a twitter conversation today and have been tinkering.

We are looking to use json schema in React components to generate input forms using react-json-schema-forms, I got this working and then started to look at code re-use. We are hoping to make use of $refs to other schema files in the code-base to maximize re-use as we have a number of common complex types.

So, I took your bundler and made a simple webpack loader In one of my components the pageProperties.schema.json is imported, this in turn references scope.schema.json

pageProperties.schema.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "title": {
      "type": "string"
    },
    "requiresScope": {
      "type": "array",
      "items": {
        "$ref": "scope.schema.json#/definitions/Scope"
      }
    }
  }
}

scope.schema.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "Scope": {
      "type": "string",
      "enum": ["user", "exec-user", "reporting-user", "admin"]
    }
  }
}

With my loader setup calling the bundler I get a bundled schema

bundle output

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "type": "object",
  "properties": {
    "title": { "type": "string" },
    "requiresScope": {
      "type": "array",
      "items": { "$ref": "scope.schema.json#/definitions/Scope" }
    }
  },
  "$defs": {
    "scope.schema.json": {
      "$id": "scope.schema.json",
      "$schema": "http://json-schema.org/draft-07/schema",
      "definitions": {
        "Scope": {
          "type": "string",
          "enum": ["user", "exec-user", "reporting-user", "admin"]
        }
      }
    }
  }
}

The pulls in the linked schema into the $defs property, however the $ref is not updated to use the bundled Based on my very limited knowledge and some runtime editing of the generated bundle it looks like the $ref needs to be updated to provide a valid pointer to the Scope which is now in the bundled schema file, i.e. "#/$defs/scope.schema.json/$defs/Scope"

jdesrosiers commented 2 years ago

The references should not be updated. They still resolve to the same place.

I suggest reading through https://json-schema.org/understanding-json-schema/structuring.html to learn more about how schema identification and referencing works. You can also read https://json-schema.org/blog/posts/bundling-json-schema-compound-documents for an explanation of how the bundling process used in this library works.

If that doesn't help explain why the references don't have to change. Let me know and I'll try to explain better.

gavinbarron commented 2 years ago

Thanks for those links, incredibly helpful.

I think I get it. Essentially when resolving a $ref the contents of $def should be checked for a pointer that matches the $ref before attempting to read it from the external location?

That closes this issue from my perspective. Do you know when was this $ref resolution behavior added to the spec? I need to work out if this is an issue that should be raised with react-json-schema-forms or if I should build a post processor to (incorrectly) patch the $refs for consumption by the forms library.

jdesrosiers commented 2 years ago

Essentially when resolving a $ref the contents of $def should be checked for a pointer that matches the $ref before attempting to read it from the external location?

Not exactly. Your bundled schema contains two schema resources: file:///path/to/pageProperties.schema.json and file://path/to/scope.schema.json. Whenever you have an $id in a sub-schema, it indicates a separate schema resource. An $id can be in any sub-schema, but there's no good reason to use it anywhere other than $defs. The scope.schema.json#/definitions/scope/ reference is in the file:///path/to/pageProperties.schema.json schema resource. So, that reference resolves to file:///path/to/scope.schema.json#/definitions/scope. Which means, the location /definitions/scope within the file:///path/to/scope.schema.json schema resource.

Do you know when was this $ref resolution behavior added to the spec?

It has always worked this way. It's standard behavior based on RFC 3986.