1

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:

  • option 1: "components/key.schema.json" and "components/data.schema.json", OR,
  • option 2: "key.schema.json" and "data.schema.json" (as shown below)

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?"
        }
      }
    }
  }
}
1

1 Answer 1

3

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:

  • from main to the other files: "$ref": "components/key.schema.json" etc
  • from the other files to each other: "$ref": "key.schema.json" etc
  • from the other files back to main: "$ref": "../main.schema.json"

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

Sign up to request clarification or add additional context in comments.

4 Comments

Great response. Quick followup question: What would change if the "$id" tag is not present in any of the documents? How would "message.schema.json" in the "components" directory reference "key.schema.json" also in the "components" directory? Would "message.schema.json" use (a) "$ref": "key.schema.json" or (b) "$ref":"components/key.schema.json"? (Let me know if the answer is long/complicated and I can submit a new question)
$id is necessary in a schema if something is to reference it. Some implementations may let you add the schema and tell it what the $id should be, but don't assume that all of them allow it.
How to do if you don't know what will be the final host to be included in $id? For example, local development vs deployment.
If everything shares the same prefix, just use relative references. But if you use something else, you're going to have a bad time -- how can you expect that your application can find resources if you name your files with an absolute prefix that your it doesn't know?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.