You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Well, I have to say that I'm somehow disappointed. draft-08's focus is schema reuse
and I don't see any improvement. Here are some proposals, which will "help" reusability
Yes, the name is no longer required because was overwritten by extended-user's $merge.
So it doesn't work how you expect. Wait! I could use as an allOf and put there the required.
And if the user also have an allOf? You guessed, the same problem, so it won't work.
Don't dispare, it's not all lost. Here comes $patch:
If you still think that it is readable, try adding three more properties to extended-user.
For a better taste just use a pinch of remove operation.
Now just do the same in other schemas and after two months you'll loose your time
trying to understand what that schema really does.
Probably you'll end up moving the properties from user to extended-user just because it is easier to read and debug.
Ok, in order to also make name required you have to manually add it.
Also you have to manually add additionalProperties. But what if user also have an allOf?
This one is a little bit trickier. You can use it in conjunction with allOf, anyOf, oneOf.
The ideea is that unevaluatedProperties knows what properties from ***Of were checked.
Well, it will not work because user has additionalProperties set to false.
Anyway, the working design for unevaluatedProperties is not in our case.
It cannot be used for extending, only for ignoring this or that but in a limited way, because it will produce unexpected behaviour eventually.
Here it is an example of usage (we don't care about user schema for now)
{
"common": "this is common and required",
"foo": 1
}
2 - valid (common & second item of anyOf)
{
"common": "this is common and required",
"bar": "bar value",
"baz": 1
}
3 - valid (common & second item of anyOf, baz is not required)
{
"common": "this is common and required",
"bar": "bar value"
}
4 - invalid (baz is not present in first item of anyOf and bar is not present in the second one)
{
"common": "this is common and required",
"foo": 1,
"baz": 1
}
5 - ???
{
"common": "this is common and required",
"foo": 1,
"bar": "bar value",
"baz": 1
}
Well, in theory this should be valid. unevaluatedProperties must know what properties were checked.
But, if an implementation of json-schema decides to do some optimizations, this will not work anymore. In case of anyOf once you've found a valid schema it will not make sense to check remaining schemas.
So, if json-schema doesn't allow optimizations by design it means that apps using it will spend most of the time checking things that don't make sense checking.
And if this is the case, you better start typing if-else and forget about json-schema.
I know that this example is too simple, and it doesn't make sense to just validate again
if name is a string since you already checked full-name, but what if user schema
also contains an allOf? What if the constraints for name are more complex?
Here is a more complex example (using two base schemas for our extended-user schema)
{
"$id": "user",
"type": "object",
"properties": {
"name": {"type": "string"},
"active": {"type": "boolean"},
"required": ["name", "active"]
},
"allOf": [
... other checks for user
],
"additionalProperties": false
}
As you can see, with $map you can add only what properties you want, you can handle nested properties, you can provide default values, and you can even use $each to map arrays.
The advantage is that I can change extended-user schema however I want without touching user and user-permissions schemas.
And for validation this is verbose, clear and flexible.
Anyway, another method you can use to simplify your schemas is using $ref together with $vars.
Without $vars you'll probably need an anyOf or oneOf which will be very slow.
But in this way you can add as many definitions as you want to settings-type schema,
or even better (and recommended), you can use different schema files for each type
and load only needed schemas, because it doesn't make sanse to load and check things that
will never change the final result.
The text was updated successfully, but these errors were encountered:
Well, I have to say that I'm somehow disappointed. draft-08's focus is schema reuse
and I don't see any improvement. Here are some proposals, which will "help" reusability
Ok, now lets take it one by one, but first I'll define the reused schema:
$merge & $patch
Extending it with
$merge
The result is
Yes, the
name
is no longer required because was overwritten byextended-user
's$merge
.So it doesn't work how you expect. Wait! I could use as an
allOf
and put there therequired
.And if the
user
also have anallOf
? You guessed, the same problem, so it won't work.Don't dispare, it's not all lost. Here comes
$patch
:Now, isn't that readable?
If you still think that it is readable, try adding three more properties to
extended-user
.For a better taste just use a pinch of
remove
operation.Now just do the same in other schemas and after two months you'll loose your time
trying to understand what that schema really does.
Probably you'll end up moving the properties from
user
toextended-user
just because it is easier to read and debug.$spread
Extending it with
$spread
The result is
Ok, in order to also make
name
required you have to manually add it.Also you have to manually add
additionalProperties
. But what ifuser
also have anallOf
?Yes, you guessed, it won't work.
unevaluatedProperties
This one is a little bit trickier. You can use it in conjunction with
allOf
,anyOf
,oneOf
.The ideea is that
unevaluatedProperties
knows what properties from***Of
were checked.Extending it with
unevaluatedProperties
Well, it will not work because
user
hasadditionalProperties
set tofalse
.Anyway, the working design for
unevaluatedProperties
is not in our case.It cannot be used for extending, only for ignoring this or that but in a limited way, because it will produce unexpected behaviour eventually.
Here it is an example of usage (we don't care about
user
schema for now)Examples of data
1 - valid (common & first item of
anyOf
)2 - valid (common & second item of
anyOf
)3 - valid (common & second item of
anyOf
, baz is not required)4 - invalid (baz is not present in first item of
anyOf
and bar is not present in the second one)5 - ???
Well, in theory this should be valid.
unevaluatedProperties
must know what properties were checked.But, if an implementation of json-schema decides to do some optimizations, this will not work anymore. In case of
anyOf
once you've found a valid schema it will not make sense to check remaining schemas.So, if json-schema doesn't allow optimizations by design it means that apps using it will spend most of the time checking things that don't make sense checking.
And if this is the case, you better start typing if-else and forget about json-schema.
Epilogue
Maybe you saw, but we already added a new keyword
$map
(besides$filters
and$vars
)for opis/json-schema to allow a simple extending.
$map
solves the following problem:Given a schema and an object, map the properties of the object to match the schema properties.
So, if the schema is:
and the current object is
you can validate it using
$ref
and$map
Please note that inside
$map
(and$vars
) the$ref
property is a (relative) json pointer forcurrent object.
Here is how we can extend the
user
You can even have other property for
name
in your extended schemaI know that this example is too simple, and it doesn't make sense to just validate again
if
name
is a string since you already checkedfull-name
, but what ifuser
schemaalso contains an
allOf
? What if the constraints forname
are more complex?Here is a more complex example (using two base schemas for our extended-user schema)
Our extended user
So if the data for
extended-user
schema isthe mapped data provided to
user
schema (first item ofallOf
) will beand the mapped data provided to
user-permissions
schema (second item ofallOf
) will beAs you can see, with
$map
you can add only what properties you want, you can handle nested properties, you can provide default values, and you can even use$each
to map arrays.The advantage is that I can change
extended-user
schema however I want without touchinguser
anduser-permissions
schemas.And for validation this is verbose, clear and flexible.
Anyway, another method you can use to simplify your schemas is using
$ref
together with$vars
.Here is an example where
$vars
is handyWithout
$vars
you'll probably need ananyOf
oroneOf
which will be very slow.But in this way you can add as many definitions as you want to
settings-type
schema,or even better (and recommended), you can use different schema files for each type
and load only needed schemas, because it doesn't make sanse to load and check things that
will never change the final result.
The text was updated successfully, but these errors were encountered: