Search code examples
c#.netjson.netjsonschema

Read json-schema definition from external file throws "Could not resolve schema reference"


I'm trying to parse a json-schema file with Newtonsoft.Json.Schema library, which holds references to an external json-schema definition that I'm not able to resolve.

The two schema files are saved in separated folders and I'd like to link them keeping a relative path reference, instead of setting the full path in the template.json file.

Here's an extract of the two files:

template.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "title": "Root Schema",
  "required": [
    "author",
    "files",
  ],
  "properties": {
    "author": {
        "type": "object",
        "$ref": "./defs/definitions.json#/$defs/author"
    },
    "files": {
    ....

definitions.json

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$defs": {
        "author": {
            "type": "object",
            "default": {},
            "title": "The author Schema",
            "required": [
                "email",
                "fullname"
            ],
            "properties": {
                "email": {
                    "type": "string",
                    "title": "The email Schema"
                },
                "fullname": {
                    "type": "string",
                    "title": "The fullname Schema"
                }
            }
        },
        ...

I'm trying to parse the template.json file, in c#, with the following code

Program.cs (Extract)

string PATH_TO_TEMPLATE_DEFINITION_SCHEMA = "./res/template.json";
var schema = JSchema.Parse(File.ReadAllText(PATH_TO_TEMPLATE_DEFINITION_SCHEMA));

The project folder structure is the following:

MyProjectFolder
|__ Program.cs
|__ res/
     |__ template.json
|__ defs/
     |__ definitions.json

I'm currently getting a could not resolve schema reference error, I tried all the possible combination in the $ref value in terms of relativeness, folder, slashes and so on.

Newtonsoft.Json.Schema.JSchemaReaderException: 'Could not resolve schema reference 'defs/definitions.json#/$defs/author'. Path 'properties.author', line xx, position yy.'

Any idea? I tried the solution provided here, but it is still not working.

Other tentatives, which failed:

  • copied definitions.json file in the root and in the res folders, no luck
  • tried file:./defs/definitions.json#/$defs/author
  • tried to use backslashes instead of slashes in the path

Any help is appreciated, thank you


Solution

  • Unfortunately, most JSON Schema libraries don't natively understand the filesystem. I'm not familiar with the capabilities of this particular library, but it looks like it doesn't. I notice that you pass the schema to the library, but not the schema's location, so the library doesn't know what the reference is relative to.

    Often an implementation will allow you to load the schema given the file location or allows you to pass the location of the schema when you pass the schema. This location would be in the form of a URI using the file: scheme. So, your "template" schema is located at file:///path/to/MyProjectFolder/res/template.json. The reference to the author schema needs to be relative to that URI, which would be ../defs/definitions.json#/$defs/author. However, just having the right reference doesn't mean the library knows how to access the filesystem to load that schema. Most libraries expect you to manually load any schemas you intend to reference.

    If the library doesn't support file references, you probably need to give them an identifier such as https://myproject.com/res/template.json and https://myproject.com/defs/definitions.json. You do this by adding the $id keyword with those URIs in each of your schemas. With this method, you can use the same relative reference from the previous paragraph. The library usually has a method you can call to load these schemas individually before validating the main schema. Note that those being https: URIs doesn't mean you need to host them somewhere. They're just a name for the schema that needs to be in the form of a URI.