How can I compile a subset of a JSON Schema with Ajv?

1.4k views Asked by At

I have to following JSON Schema:

{
  "type": "object",
  "required": [
    "type",
    "title"
  ],
  "properties": {
    "type": {
      "enum": [
        "journal",
        "book",
        "generic"
      ]
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    }
  }
}

According to that schema, the following object is valid:

{type: 'journal', title: 'foo'}

And this one isn't:

{type: 'qux', title: ''}

Is there a way I can reuse subsets of that schema so that I can also validate types and titles individually?

e.g. (in pseudo code)

const Ajv = require('ajv');
const ajv = new Ajv;

ajv.addSchema(/* see schema above */);

const validate_document = ajv.compile(/* see schema above */);
const validate_type = ajv.compile(/* reuse corresponding subset */);
const validate_title = ajv.compile(/* reuse corresponding subset */);

validate_document({type: 'qux', title: ''}); // false
validate_type('qux'); // false
validate_title(''); // false
1

There are 1 answers

1
customcommander On BEST ANSWER

I settled on this solution which allows me to keep the schema "integrity" (I don't need to split it into smaller parts so that it remains easy to read and understand). All I needed to do is to set $id keys on the relevant schemas:

{
  "$id": "document",          <-- id for the whole schema
  "type": "object",
  "required": [
    "type",
    "title"
  ],
  "properties": {
    "type": {
      "$id": "document-type", <-- id for the type schema
      "enum": [
        "journal",
        "book",
        "generic"
      ]
    },
    "title": {
      "$id": "document-title", <-- id for the title schema
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    }
  }
}

Ajv allows you to reference a schema by its id in Ajv#getSchema which compiles a schema into a validation function:

const validate_document = ajv.getSchema('document');
const validate_type = ajv.getSchema('document-type');
const validate_title = ajv.getSchema('document-title');

console.log(
    'Is {type: "journal", title: "foo"} valid? '
  , validate_document({type: "journal", title: "foo"})
); // true

console.log(
    'Is "qux" a valid document type? '
  , validate_type("qux")
); // false

console.log(
    'Is "journal" a valid document type? '
  , validate_type("journal")
); // true

console.log(
    'Is "" a valid document title? '
  , validate_title("")
); // false

console.log(
    'Is "foo" a valid document title? '
  , validate_title("foo")
); // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.11.0/ajv.min.js"></script>
<script>
const ajv = new Ajv;

ajv.addSchema({
  "$id": "document",
  "type": "object",
  "required": [
    "type",
    "title"
  ],
  "properties": {
    "type": {
      "$id": "document-type",
      "enum": [
        "journal",
        "book",
        "generic"
      ]
    },
    "title": {
      "$id": "document-title",
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    }
  }
});

</script>