jsonschemajson-schema-validatorjsonschema2pojopython-jsonschemanjsonschema

JSON Schema relative references resolution


I am trying to define a valid JSON Schema and I am not sure how to structure the reference ("$ref") values when referenced components are in sub-directories. I have read (at length) the info at the official JSON Schema site as well as examined test data from the various JSON Schema parsers out there, but the available info is either unclear or unavailable (or, of course, I could not find it despite hours of searching)...

The specific help I need is to confirm whether the references for files in a component directory - which references files in the components directory - should be defined with "components" in the reference or not. (Note that $id is not available to provide a base URI).

In other words, should the reference in "message.schema.json" be:

In option 1, the "$ref" is relative to the parent ("main.schema.json"), and in option 2 it is relative to the current path ("message.schema.json").

Below is information to provide further context.

The file structure is relatively simple and is illustrated below:

main.schema.json
  - message.schema.json
  - key.schema.json
  - data.schema.json

The contents of the files are shown below...

main.schema.json:

{
  "$id": "https://example.com/arrays.schema.json",
  "description": "main.schema.json",
  "type": "object",
  "required": [ "messages" ],
  "properties": {
    "messages": {
      "type": "array",
      "items": { "$ref": "components/message.schema.json" }
    }
  }
}

The above JSON Schema references files in the "components" directory (a directory under the main.schema.json file).

message.schema.json:

{
  "$id": "https://example.com/arrays.schema.json",
  "description": "message.schema.json",
  "type": "object",
  "required": [ "message" ],
  "properties": {
    "message": {
      "type": "object",
      "required": [ "key", "data" ],
      "properties": {
        "key": {
          "$ref": "key.schema.json"
        },
        "data": {
          "$ref": "data.schema.json"
        }
      }
    }
  }
}

And the above message.schema.json references the following components that are in the same directory as the message.schema.json file:

key.schema.json:

{
  "$id": "https://example.com/arrays.schema.json",
  "description": "key.schema.json",
  "type": "object",
  "required": [ "key" ],
  "properties": {
    "key": {
      "type": "string"
    }
  }
}

data.schema.json:

{
  "$id": "https://example.com/arrays.schema.json",
  "description": "data.schema.json",
  "type": "object",
  "required": [ "data" ],
  "properties": {
    "data": {
      "type": "object",
      "required": [ "veggieName", "veggieLike" ],
      "properties": {
        "veggieName": {
          "type": "string",
          "description": "The name of the vegetable."
        },
        "veggieLike": {
          "type": "boolean",
          "description": "Do I like this vegetable?"
        }
      }
    }
  }
}

Solution

  • Why do all your schemas have the same $id? Many implementations will error on that, or cause them to "forget" about earlier schemas as you load later ones with the same identifier.

    I'm not sure if you're thinking that the description keyword is being used here, but it isn't. The keyword that matters is $id, and its value is used as the base for future URI resolution such as those found in $ref.

    Depending on which particular implementation you're using, you either need to make sure that the URIs in the $id keywords are properly resolveable (that is, if you go to the URL "https://example.com/message.schema.json" it will actually download something), or you need to manually load all your files into the implementation before beginning evaluation. Implementations are not required by the specification to support network resolution, but they are required to support some sort of mechanism for pre-loading schemas under their canonical identifiers.

    If you use these values as $ids (replacing example.com with a more appropriate host):

    ..then all references from main to the other files can be made via uri references:

    And you of course can use the full absolute URIs in all $refs as well.