Open meskill opened 2 months ago
possible fix in https://github.com/GREsau/schemars/pull/318
This is a valid bug, but I think fixing it may be quite complicated. It's also related to #48 in that it depends on the deserialize vs serialize behaviour we're trying to describe.
Consider these types:
#[derive(JsonSchema)]
pub struct MyStruct {
pub my_int: i32,
#[schemars(flatten)]
pub enum1: Option<MyEnum1>,
#[schemars(flatten)]
pub enum2: Option<MyEnum1>,
}
#[derive(JsonSchema)]
pub enum MyEnum1 {
Foo(i32),
Bar(i32),
Foobar(i32),
}
#[derive(JsonSchema)]
pub enum MyEnum2 {
Baz(i32),
Qux(i32),
}
What should the schema for MyStruct
look like?
When serialized to JSON, the value will be an object that must contain the properties:
my_int
Foo
, Bar
or Foobar
Baz
or Qux
There are several ways to represent that schema. For example, using dependentSchemas
to disallow the mutually-exclusive properties:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "MyStruct",
"type": "object",
"properties": {
"my_int": {
"type": "integer",
"format": "int32"
},
"Foo": {
"type": "integer",
"format": "int32"
},
"Bar": {
"type": "integer",
"format": "int32"
},
"Foobar": {
"type": "integer",
"format": "int32"
},
"Baz": {
"type": "integer",
"format": "int32"
},
"Qux": {
"type": "integer",
"format": "int32"
}
},
"dependentSchemas": {
"Foo": {
"properties": {
"Bar": false,
"Foobar": false
}
},
"Bar": {
"properties": {
"Foo": false,
"Foobar": false
}
},
"Foobar": {
"properties": {
"Foo": false,
"Bar": false
}
},
"Baz": {
"properties": {
"Qux": false
}
},
"Qux": {
"properties": {
"Baz": false
}
}
},
"required": [
"my_int"
]
}
But if we're instead considering what JSON values will successfully deserialize to a MyStruct
via serde_json, then all of the following are valid:
{"my_int": 0}
{"my_int": 0, "Foo": 0, "Bar": 0, "Foobar": 0}
{"my_int": 0, "Foo": "string", "Bar": null, "Foobar": false}
So if we're strictly following the deserialization behaviour, then the schema would be:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "MyStruct",
"type": "object",
"properties": {
"my_int": {
"type": "integer",
"format": "int32"
}
},
"required": [
"my_int"
]
}
...which seems much less useful
This is a special case of https://github.com/GREsau/schemars/issues/48, but I'll leave this issue open because it's a complicated case in itself, and I don't want to further overcomplicate the other issue
Consider the next types:
The generated schema looks like
Hence, forcing the value from enum to be specified by the schema i.e. basically ignoring
Option
Serde handles this cases properly by handling optional case. Check the playground