Json schema provides a default for an object but not for its properties - jsonschema

I have a property somewhere in my JSON schema that is of type "object" and has a default value - an object with its properties and their values. Inside the object schema I have the properties listed and their types specified - but no defaults for them. The question is - in what will this property result if only one of the values is provided but non of the rest? Will they default to what they would if noting was provided?
"autoStart": {
"type": "object",
"default":{
"foo": true,
"bar": 3
},
"properties":{
"foo": {
"type": "boolean"
},
"bar": {
"type": "number"
}
}
}
If the provided json is
"autoStart": {
"foo": false
}
what will happen to the "bar"?

What does default do? Nothing according to the specification
default is an annotation keyword. An annotation is to provide information to an implementation or application so they can define their own additional behaviour. This means any behaviour which does ANYTHING with default is implementation or application specific.
Let's look at what the spec says...
There are no restrictions placed on the value of this keyword.
When multiple occurrences of this keyword are applicable to a
single sub-instance, implementations SHOULD remove duplicates.
This keyword can be used to supply a default JSON value associated
with a particular schema. It is RECOMMENDED that a default value be
valid against the associated schema.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-10.2
Besides annotation collection and return, there's nothing an implementation should be expected to DO with an annotation keyword, apart from that which it defines in its own documentation.

Related

What is the best way to validate that all values in a dictionary adhere to a JSON schema?

I want to validate that all values in a dictionary adhere to a schema while the keys can be whatever. Is there a better way to do this than just using a pattern that matches everything:
"foo": {
"type": "object",
"patternProperties": {
"^.*$": {
"$ref": "#/$defs/bar"
}
}
}
Using patternProperties like you're doing is that best way, although you can simplify the regex to an empty string because regexes aren't implicitly anchored in JSON Schema.
{
"type": "object",
"patternProperties": {
"": { "$ref": "#/$defs/bar" }
}
}
The other option is to use additionalProperties, which is less verbose, but can lead to bugs.
{
"type": "object",
"additionalProperties": { "$ref": "#/$defs/bar" }
}
The problem with this is that it's only accidentally the behavior you really want. What you want is to validate all properties against this schema. additionalProperties validates only the properties that aren't declared with properties or patternProperties. If later someone wants to add an additional constraint to a specific property and adds properties, they're going to break this schema unless they rewrite the additionalProperties using patternProperties.
It's one of those small things that's an unlikely to occur, but when it does, it's been known to be a source of bugs.
I would suggest to use the additionalProperties keyword where you can also set a schema. More details here
Using patternProperties, the validator needs to run a RegExp check for each property which takes time.

How can I use serde to deserialize into a hierarchical decentralized configuration? [duplicate]

This question already has answers here:
How can deserialization of polymorphic trait objects be added in Rust if at all?
(3 answers)
How do I deserialize into trait, not a concrete type?
(3 answers)
Closed 2 years ago.
I want to have a JSON config file of the form:
{
"general_option_foo": true,
"general_option_bar": "hello world!",
"modules": [
{ "name": "moduleA", "module_options" : {"optFoo":"foo"} },
{ "name" : "moduleB", "module_options" : {"optBar":[3,4], "optBuzz": true} }
{ "name": "moduleA", "module_options" : {"optFoo":"bar"} },
]
}
My application supports many different modules that are each configurable, and which get instantiated how many times and with what options should be determined by the config file.
With serde, everything will work fine if I make one giant struct that contains everything, but I want a more modular design. The creator of each module should be able to define a serializable struct for their module's parameters without having to look at the others. In particular, I am looking to avoid having one big central enum with all modules, I want to use trait based polymorphism instead.
How do I deserialize into trait, not a concrete type? is similar, but all the answers fall back to using a central enum.
I believe what I want is something like:
#[derive(Deserialize)]
struct ModuleConfig {
name: String,
module_options: Box<dyn Deserialize>,
}
#[derive(Deserialize)]
struct GeneralOptions {
general_option_foo: bool,
general_option_bar: String,
modules: Vec<ModuleConfig>,
}
I assume serde is going to need some help with using the module name to look up the corresponding trait impl to actually do the deserialization. Is this possible? Is there a good example somewhere I could work from?

Using JSON Schema, how do I validate an object where keys and values are not known in advance?

i need to validate this format:
{
"variables": {
"team": "red",
"L3_HCU_TESTS": "N",
"dbo_user": "user",
"version": 920
}
}
I don't know in advance names of keys and values.
"variables" are not mandatory but if it's provided,
keys can be any string, and value can be any value.
What is important for me is to validate that "variables" (if provider) will include key and value.
Empty values are not allowed
With a JSON Object, the keys MUST be a string, so your requirement for string based keys is already covered by "is valid JSON".
Expanding your requirements, you want:
"variables" must be an object
There must be at least one property in the object
The value of the properties must not be null
Here's a schema which satisfies those requirements:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"variables": {
"type": "object",
"minProperties": 1,
"additionalProperties": {
"not": {
"type": "null"
}
}
}
}
}
You can test it against your instance using this link.
"type": "object" makes sure that "variables" is an object.
"minProperties" makes sure there is a minimum number of properties in an object.
"additionalProperties" value subschema is applied to all key values in the object (as "properties" and "patternProperties" are not defined). The subschema inverts the result of a subschema, which defines the type must be null. The inversion results in, must be NOT NULL.
I haven't seen minProperties used very often. Here's the reference link for that JSON Schema keyword: https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.2

Ignoring null fields when deserializing with Jackson

I have the following Kotlin data class:
data class TestObject(
val boolField: Boolean,
val stringField: String,
val nullBoolField: Boolean = true,
val nullStringField: String = "default",
val notThereBoolField: Boolean = true,
val notThereStringField: String = "not there"
)
I am then attempting to deserialize some JSON into this class using Jackson v2.9.4 with the Jackson Kotlin plugin v2.9.4.1. The test JSON is as follows:
{
"boolField": true,
"stringField": "string",
"nullBoolField": null,
"nullStringField": null
}
The first two and the last two fields deserialize successfully - with the values from the JSON and the default values from the Kotlin data class, as appropriate. However, when the middle pair of fields are present, the deserialization fails with:
Instantiation of [simple type, class com.example.TestObject] value
failed for JSON property nullStringField due to missing (therefore
NULL) value for creator parameter nullStringField which is a
non-nullable type
I know I could solve the problem by changing the types of nullBoolField and nullStringField to Boolean? and String? respectively, but since default values are known I would rather not have to push the handling of null further down into the code by doing that.
The question is: is there any way of configuring Jackson to use the Kotlin data class default values for non-nullable properties when the property is present in the JSON but set to null?
You could try first to filter null values from json and after to deserialize it to Kotlin object.
Or you may to try add feature to kotlin-jackson module, with adding a new feature parameter, which will enable a null ignoring from json parameters and use default values.
You may do this by modify this line (if I'm not mistaken)
If you don't have any value and field is non-nullable then you should not pass it in request body:
{
"boolField": true,
"stringField": "string"
}
This results in following object, as expected:
{
"boolField": true,
"stringField": "string",
"nullBoolField": true,
"nullStringField": "default",
"notThereBoolField": true,
"notThereStringField": "not there"
}

How can I specify that an object's type is one of several possible object types?

I have an API where I post a set of object to the server, differentiated by type, where each type has some different parameters. The commands are structured like so:
{
"type": <command-name>,
"args": {
<command-specific args>
}
}
For example, these may be two possible commands:
{
"type": "Flooblinate",
"args": {
"intensity": "High",
"frequency": "Every blue moon"
}
}
{
"type": "Blagostrate",
"args": {
"temperature": 34.5,
"darkMatter": true
}
}
How can I specify this in Swagger? I can specify an enum for "type", but how do I say ""args" is one of these possible objects"?
I've checked out the docs but nothing stands out. The most promising one was allOf because it displayed nicely in the editor (pastebin, paste into the online editor):
definitions:
Product:
type: object
allOf:
- type: object
title: Flooblinate
properties:
intensity:
type: string
frequency:
type: string
- type: object
title: Blagostrate
properties:
temperature:
type: number
darkMatter:
type: boolean
Which looks like this:
However, this isn't semantically what I need, and, not surprisingly, in the online viewer (that one's not set up for my test case, not sure how to link up a local file easily), they are presented as if all the fields appear at the same time, which is of course what allOf means:
What's the proper way to represent this with Swagger?
According to input from Ron on the google group, what I want is to use the discriminator property:
definitions:
Product:
type: object
discriminator: type
properties:
type: string
required: [type]
Flooblinate:
allOf:
- $ref: '#/definitions/Product'
- type: object
properties:
intensity:
type: string
frequency:
type: string
Blagostrate:
allOf:
- $ref: '#/definitions/Product'
- type: object
properties:
temperature:
type: number
darkMatter:
type: boolean
Semantically this means what I want it to mean. I should specify $ref: '#/definitions/Product' wherever the API accepts or returns any one of Flooblinate or Blagostrate. Note this requires a field (called type here) on the objects to act as the discriminator.
I thought this may be the approach, but the tools didn't show what I expected. However:
That's because the tools are not 100% in support of the discriminator yet - however, that's the right way to describe your use case.
Once you define the discriminator in the top level model, anything that 'allOf's it will be considered a viable option, and indeed you're refer to the top level model for usage.