What is wrong with this JSON Type Definition?

168 views Asked by At

I have some code to create and validate a JSON schema that should represent a tagged union. I want the direction prop value to be lt, gt, or et, and depending on that value the object would contain certain other props like amount or range:

import Ajv from "ajv/dist/jtd"
const ajv = new Ajv()

const Filter = {
    "discriminator": "direction",
    "mapping": {
        "gt": {
            "properties": {
                "amount": { "type": "number" }
            }
        },
        "lt": {
            "properties": {
                "amount": { "type": "number" }
            }
        },
        "et": {
            "properties": {
                "range": {
                    "properties": {
                        "top": { "type": "number" },
                        "bottom": { "type": "number" }
                    }
                }
            }
        }
    }
};

const validateFilter = ajv.compile(Filter);

Results in:

Error: schema is invalid: 
data/discriminator must NOT have additional properties, 
data must have property 'ref', 
data must have property 'type', 
data must have property 'enum', 
data must have property 'elements', 
data must have property 'properties', 
data must have property 'optionalProperties', 
data/mapping/gt/properties/amount/type must NOT have additional properties, 
data/mapping/gt/properties/amount must have property 'ref', 
data/mapping/gt/properties/amount/type must be equal to one of the allowed values, 
data/mapping/gt/properties/amount must have property 'enum', 
data/mapping/gt/properties/amount must have property 'elements', 
data/mapping/gt/properties/amount must have property 'properties', 
data/mapping/gt/properties/amount must have property 'optionalProperties', 
data/mapping/gt/properties/amount must have property 'discriminator', 
data/mapping/gt/properties/amount must have property 'values', 
data/mapping/gt/properties/amount must match a schema in union, 
data/mapping/gt must have property 'optionalProperties', 
data/mapping/gt must match a schema in union, 
data must have property 'values', 
data must match a schema in union

I'm lost as to why this is happening. Here's a sandbox to mess with: https://codesandbox.io/s/ajv-errors-54rdmx

1

There are 1 answers

1
TBA On

Note that ajv offers limited support for discriminator keyword. However, if I understand correctly the tagged union you are trying to validate, here's an example for such validation filter (without using mapping which is not supported)

// To use discriminator keyword you have to set discriminator: true with Ajv constructor: it is not enabled by default.
const ajv = new Ajv({ discriminator: true });

const Filter = {
    type: 'object',
    discriminator: { propertyName: 'direction' },
    required: ['direction'],
    oneOf: [
        {
            required: ['amount'],
            properties: {
                direction: { enum: ['gt', 'lt'] },
                amount: { type: 'number' }
            }
        },
        {
            required: ['range'],
            properties: {
                direction: { const: 'et' },
                range: {
                    type: 'object',
                    properties: {
                        top: { type: 'number' },
                        bottom: { type: 'number' }
                    }
                }
            }
        },
    ]
};

const validateFilter = ajv.compile(Filter);

// valid filters:
// { direction: 'gt', amount: 10 }
// { direction: 'lt', amount: -1 }

// invalid filters:
// { direction: 'gt' }
// { direction: 'lt', amount: false }