For the libraries that have playgrounds, none of them seem to have support for Pydantic's anyOf field, like so:
{
"timeout": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "The timeout for the command; returns an empty result on failure.",
"title": "Timeout"
}
}
Most libraries don't interpret this as an optional integer field, but instead try and make two options with auto-generated names.
It may be the case that we'll have to either mess with how Pydantic generates these or add some functionality after the fact. We may also just have to deal with it and not use Optional in anything that's going to be used to generate a form.
The cleanest route (allowing nulls and using required where possible) may just be to revalidate every field before it is presented to the frontend. If anyOf is seen, and all elements in the list are just one-element dictionaries with the key type, delete anyOf and replace it with the first non-null type present. For our example, it'd then look like
{
"timeout": {
"type": "integer"
"default": null,
"description": "The timeout for the command; returns an empty result on failure.",
"title": "Timeout"
}
}
This would no longer be correct semantically - after all, null is not an integer. But it fixes our problems without having to invent a new type in Pygin just for the sake of getting forms all the way up in frontend land to work. That said, the schemas are only intended for generating forms in the frontend anyways, so does it really matter?
Assuming that we don't find a library that supports anyOf over types, we have a few options:
Modify Pygin to use a custom schema generator when dumping metadata, stripping the anyOf type and selecting the first non-null type in a dict of two types instead
Modify the backend so that before it presents the schema to the frontend, it scans for this metadata and performs the replacement if deemed necessary; use the original schema for validation. (This allows Pygin to retain default Pydantic behavior, and allows other libraries like jsonschema to still perform validation.)
Option 1 removes the need for this flaky pre-processing, and if things break, it's really easy to fix. Option 2 preserves more of the typing and allows validation to correctly take place, while still allowing these fields to be absent when passed into BaseModel.model_validate() (since Pydantic will just default to None). This allows other theoretical validators to continue using the "correct" schema, while scoping our monkeypatching to just the frontend.
Pydantic issue 7161 (not linking to avoid visibility) describes this in more detail.
https://jsonforms.io/ is the generally accepted solution, but it only supports React/Angular/Vue with no known Svelte bindings. Some smaller projects, like https://github.com/webgme/svelte-jsonschema-form and https://github.com/restspace/svelte-schema-form have been developed for Svelte, and there's also more specialized libraries like https://rjsf-team.github.io/react-jsonschema-form/ (for React) and https://jsonform.github.io/jsonform/playground/index.html?example=schema-basic that's entirely client-side, but uses a slightly different structure than
For the libraries that have playgrounds, none of them seem to have support for Pydantic's
anyOf
field, like so:Most libraries don't interpret this as an optional integer field, but instead try and make two options with auto-generated names.
It may be the case that we'll have to either mess with how Pydantic generates these or add some functionality after the fact. We may also just have to deal with it and not use
Optional
in anything that's going to be used to generate a form.The cleanest route (allowing nulls and using
required
where possible) may just be to revalidate every field before it is presented to the frontend. IfanyOf
is seen, and all elements in the list are just one-element dictionaries with the keytype
, deleteanyOf
and replace it with the first non-null type present. For our example, it'd then look likeThis would no longer be correct semantically - after all,
null
is not an integer. But it fixes our problems without having to invent a new type in Pygin just for the sake of getting forms all the way up in frontend land to work. That said, the schemas are only intended for generating forms in the frontend anyways, so does it really matter?Assuming that we don't find a library that supports
anyOf
over types, we have a few options:anyOf
type and selecting the first non-null type in a dict of two types insteadjsonschema
to still perform validation.)Option 1 removes the need for this flaky pre-processing, and if things break, it's really easy to fix. Option 2 preserves more of the typing and allows validation to correctly take place, while still allowing these fields to be absent when passed into
BaseModel.model_validate()
(since Pydantic will just default to None). This allows other theoretical validators to continue using the "correct" schema, while scoping our monkeypatching to just the frontend.Pydantic issue 7161 (not linking to avoid visibility) describes this in more detail.