Search code examples
jsonjsonschemajson-schema-validator

How to create a dialect of the draft 2020-12 JSON Schema meta-schema?


I want to create a dialect of the draft-2020-12 meta-schema. I want the dialect to prohibit the use of any of the properties (title, description, default, etc.) in the "meta-data" meta-schema. In other words, I want the meta-data vocabulary deleted from the "main" meta-schema:

"$vocabulary": {
    ...
    "https://json-schema.org/draft/2020-12/vocab/meta-data": true

How to do that? What are the list of steps needed to create this new meta-schema dialect? @Jason Desrosiers wrote a terrific list of steps (https://stackoverflow.com/a/63797644/1248535) for creating a dialect of the draft04 meta-schema. I am guessing that the list of steps for creating a dialect of the draft-2020-12 meta-schema is quite different.


Solution

  • There's actually a pretty good example in the spec.

    Starting with 2019-09, we broke the meta-schema into several, one for each vocabulary. The first thing to do is remove the things you don't want.

    Start with the 2020-12 base meta-schema.

    {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$id": "https://json-schema.org/draft/2020-12/schema",
      "$vocabulary": {
        "https://json-schema.org/draft/2020-12/vocab/core": true,
        "https://json-schema.org/draft/2020-12/vocab/applicator": true,
        "https://json-schema.org/draft/2020-12/vocab/unevaluated": true,
        "https://json-schema.org/draft/2020-12/vocab/validation": true,
        "https://json-schema.org/draft/2020-12/vocab/meta-data": true,
        "https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
        "https://json-schema.org/draft/2020-12/vocab/content": true
      },
      "$dynamicAnchor": "meta",
    
      "title": "Core and Validation specifications meta-schema",
      "allOf": [
        {"$ref": "meta/core"},
        {"$ref": "meta/applicator"},
        {"$ref": "meta/validation"},
        {"$ref": "meta/meta-data"},
        {"$ref": "meta/format-annotation"},
        {"$ref": "meta/content"}
      ],
      "type": ["object", "boolean"]
      // there's some other "deprecated" stuff in here that you likely don't need
    }
    

    You don't want the meta-data vocabulary, so remove references to that. You should also change the $id because this is your meta-schema now, not the draft 2020-12 meta-schema.

    {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$id": "https://your.domain/meta-schema/or/something",
      "$vocabulary": {
        "https://json-schema.org/draft/2020-12/vocab/core": true,
        "https://json-schema.org/draft/2020-12/vocab/applicator": true,
        "https://json-schema.org/draft/2020-12/vocab/unevaluated": true,
        "https://json-schema.org/draft/2020-12/vocab/validation": true,
        "https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
        "https://json-schema.org/draft/2020-12/vocab/content": true
      },
      "$dynamicAnchor": "meta",
    
      "title": "Core and Validation specifications meta-schema",
      "allOf": [
        {"$ref": "meta/core"},
        {"$ref": "meta/applicator"},
        {"$ref": "meta/validation"},
        {"$ref": "meta/format-annotation"},
        {"$ref": "meta/content"}
      ],
      "type": ["object", "boolean"]
      // there's some other "deprecated" stuff in here that you likely don't need
    }
    

    That removes the definition of those keywords, but it doesn't disallow them. Draft 2020-12 permits the inclusion of unknown keywords, so with this anyone could still just add title. What's more, since we've removed the definition for title, they can add it with whatever value they want:

    {
      "title": true
    }
    

    This would be a valid schema according to your meta-schema.

    To disallow those keywords, you have several options.

    • disallow only those specific keywords
    • disallow all unknown keywords

    Disallow only those keywords

    For this you have several options, but I think this is probably the simplest:

    {
      // rest of meta-schema
      "properties": {
        "title": false,
        ...
      }
    }
    

    It basically says that no value for these properties is valid, effectively requiring that they're not present.

    Disallow all unknown keywords

    For this approach, you'll add unevaluatedProperties: false to the meta-schema. This will disallow any keyword not defined in one of the meta-schemas listed in the allOf.

    {
      // rest of meta-schema
      "unevaluatedProperties": false
    }