Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

if/then/else + default #40

Closed
AndreKR opened this issue Oct 16, 2017 · 6 comments
Closed

if/then/else + default #40

AndreKR opened this issue Oct 16, 2017 · 6 comments

Comments

@AndreKR
Copy link

AndreKR commented Oct 16, 2017

This is a similar schema as in json-schema-org/json-schema-spec#180 (comment):

var Ajv = require('ajv');

var schema = {
	"properties": {
		"foo": {
			"type": "integer"
		},
		"bar": {
			"type": "integer",
			"default": 1
		},
		"pets": {
			"type": "array",
			"items": {
				"oneOf": [
					{
						"if": { "properties": { "type": { "const": "cat" } } },
						"then": { "$ref": "#/definitions/cat_pet" },
						"else": false
					},
					{
						"if": { "properties": { "type": { "const": "snake" } } },
						"then": { "$ref": "#/definitions/snake_pet" },
						"else": false
					}
				]
			}
		}
	},
	"definitions": {
		"cat_pet": {
			"type": "object",
			"properties": {
				"type": { "type": "string", "const": "cat" },
				"fur_color": { "type": "string", "enum": ["black", "white", "orange"], "default": "black" }
			},
			"required": ["type", "fur_color"]
		},
		"snake_pet": {
			"type": "object",
			"properties": {
				"type": { "type": "string", "const": "snake" },
				"overall_length": { "type": "integer", "minimum": 1, "default": 1 }
			},
			"required": ["type", "overall_length"]
		}
	}
};

data = {
	"foo": 123,
	"pets": [
		{
			"type": "cat",
			"fur_color": "white",
			"inv": "alid"
		},
		{
			"type": "snake",
			"inv": "alid"
		}
	]
};

var ajv = new Ajv({removeAdditional: true, useDefaults: true});
require('ajv-keywords')(ajv, 'if');
var validate = ajv.compile(schema);
var valid = validate(data);
console.log(data);
if (!valid) console.log(validate.errors);

This time I try to have Ajv coerce the data into a valid structure, but I get errors:

[ { keyword: 'switch',
    dataPath: '.pets[1]',
    schemaPath: '#/properties/pets/items/oneOf/0/switch',
    params: { caseIndex: 1 },
    message: 'should pass "switch" keyword validation' },
  { keyword: 'if',
    dataPath: '.pets[1]',
    schemaPath: '#/properties/pets/items/oneOf/0/if',
    params: { keyword: 'if' },
    message: 'should pass "if" keyword validation' },
  { keyword: 'required',
    dataPath: '.pets[1]',
    schemaPath: '#/definitions/snake_pet/required',
    params: { missingProperty: 'overall_length' },
    message: 'should have required property \'overall_length\'' },
  { keyword: 'if',
    dataPath: '.pets[1]',
    schemaPath: '#/properties/pets/items/oneOf/1/if',
    params: { keyword: 'if' },
    message: 'should pass "if" keyword validation' },
  { keyword: 'oneOf',
    dataPath: '.pets[1]',
    schemaPath: '#/properties/pets/items/oneOf',
    params: {},
    message: 'should match exactly one schema in oneOf' } ]
@epoberezkin
Copy link
Member

"default" is ignored inside oneOf - see https://github.com/epoberezkin/ajv#assigning-defaults

You can safely use "allOf" - then defaults inside "then" will be applied.

@epoberezkin
Copy link
Member

epoberezkin commented Oct 16, 2017

You can't use allOf as is, but you can restructure the schemas so you don't have else's and then use allOf.

@AndreKR
Copy link
Author

AndreKR commented Oct 16, 2017

I don't get it. You don't mean this, do you?

var schema = {
	"properties": {
		"foo": {
			"type": "integer"
		},
		"bar": {
			"type": "integer",
			"default": 1
		},
		"pets": {
			"type": "array",
			"items": {
				"allOf": [
					{
						"if": { "properties": { "type": { "const": "cat" } } },
						"then": { "$ref": "#/definitions/cat_pet" }
					},
					{
						"if": { "properties": { "type": { "const": "snake" } } },
						"then": { "$ref": "#/definitions/snake_pet" }
					}
				]
			}
		}
	},
	"definitions": {
		"cat_pet": {
			"type": "object",
			"properties": {
				"type": { "type": "string", "const": "cat" },
				"fur_color": { "type": "string", "enum": ["black", "white", "orange"], "default": "black" }
			},
			"required": ["type", "fur_color"]
		},
		"snake_pet": {
			"type": "object",
			"properties": {
				"type": { "type": "string", "const": "snake" },
				"overall_length": { "type": "integer", "minimum": 1, "default": 1 }
			},
			"required": ["type", "overall_length"]
		}
	}
};
[ { keyword: 'required',
    dataPath: '.pets[1]',
    schemaPath: '#/definitions/snake_pet/required',
    params: { missingProperty: 'overall_length' },
    message: 'should have required property \'overall_length\'' },
  { keyword: 'if',
    dataPath: '.pets[1]',
    schemaPath: '#/properties/pets/items/allOf/1/if',
    params: { keyword: 'if' },
    message: 'should pass "if" keyword validation' } ]

@epoberezkin
Copy link
Member

Can you please try putting defaults directly in then schema (not in definitions)? (ajv-validator/ajv#337)

@AndreKR
Copy link
Author

AndreKR commented Oct 17, 2017

Both examples give the same result as before when I resolve the definitions. Here's the second (the one with allOf):

var schema = {
	"properties": {
		"foo": {
			"type": "integer"
		},
		"bar": {
			"type": "integer",
			"default": 1
		},
		"pets": {
			"type": "array",
			"items": {
				"allOf": [
					{
						"if": { "properties": { "type": { "const": "cat" } } },
						"then": {
							"type": "object",
							"properties": {
								"type": { "type": "string", "const": "cat" },
								"fur_color": { "type": "string", "enum": ["black", "white", "orange"], "default": "black" }
							},
							"required": ["type", "fur_color"]
						}
					},
					{
						"if": { "properties": { "type": { "const": "snake" } } },
						"then": {
							"type": "object",
							"properties": {
								"type": { "type": "string", "const": "snake" },
								"overall_length": { "type": "integer", "minimum": 1, "default": 1 }
							},
							"required": ["type", "overall_length"]
						}
					}
				]
			}
		}
	}
};
[ { keyword: 'required',
    dataPath: '.pets[1]',
    schemaPath: '#/properties/pets/items/allOf/1/switch/0/then/required',
    params: { missingProperty: 'overall_length' },
    message: 'should have required property \'overall_length\'' },
  { keyword: 'if',
    dataPath: '.pets[1]',
    schemaPath: '#/properties/pets/items/allOf/1/if',
    params: { keyword: 'if' },
    message: 'should pass "if" keyword validation' } ]

@Vincz
Copy link

Vincz commented Nov 9, 2017

I'm facing the same issue. default doesn't seem to work in if / then regarding a previous allOf or oneOf.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants