Merge pull request #290 from GREsau/v1
Changes for v1.0.0 (still in-progress)
This commit is contained in:
commit
34914a6c50
265 changed files with 6529 additions and 6908 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
||||||
- nightly
|
- nightly
|
||||||
include:
|
include:
|
||||||
- rust: 1.60.0
|
- rust: 1.60.0
|
||||||
test_features: "--features impl_json_schema"
|
test_features: ""
|
||||||
allow_failure: false
|
allow_failure: false
|
||||||
- rust: stable
|
- rust: stable
|
||||||
test_features: "--all-features"
|
test_features: "--all-features"
|
||||||
|
|
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -1,5 +1,24 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.0.0-alpha.3] - 2024-08-10
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `#[schemars(transform = some::transform)]` for applying arbitrary modifications to generated schemas. `some::transform` must be an expression of type `schemars::transform::Transform` - note that this can be a function with the signature `fn(&mut Schema) -> ()`.
|
||||||
|
- `SchemaSettings` and `SchemaGenerator` are both now `Send`
|
||||||
|
|
||||||
|
### Changed (_⚠️ breaking changes ⚠️_)
|
||||||
|
|
||||||
|
- `visit` module and `Visitor` trait have been replace with `transform` and `Transform` respectively. Accordingly, these items have been renamed:
|
||||||
|
- `SchemaSettings::visitors` -> `SchemaSettings::transforms`
|
||||||
|
- `SchemaSettings::with_visitor` -> `SchemaSettings::with_transform`
|
||||||
|
- `SchemaGenerator::visitors_mut` -> `SchemaGenerator::transforms_mut`
|
||||||
|
- `GenVisitor` -> `GenTransform`
|
||||||
|
- `Visitor::visit_schema` -> `Transform::transform`
|
||||||
|
- `visit::visit_schema` -> `transform::transform_subschemas`
|
||||||
|
- `GenTransform` must also impl `Send`, but no longer needs to impl `Debug`
|
||||||
|
- Doc comments no longer have newlines collapsed when generating the `description` property (https://github.com/GREsau/schemars/pull/310)
|
||||||
|
|
||||||
## [1.0.0-alpha.2] - 2024-06-05
|
## [1.0.0-alpha.2] - 2024-06-05
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
105
Cargo.lock
generated
105
Cargo.lock
generated
|
@ -2,12 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arrayvec"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
|
@ -29,17 +23,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bigdecimal"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bigdecimal"
|
name = "bigdecimal"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -168,12 +151,6 @@ version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.2"
|
version = "0.14.2"
|
||||||
|
@ -196,17 +173,6 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "1.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"hashbrown 0.12.3",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
|
@ -214,8 +180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
|
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.2",
|
"hashbrown",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -284,29 +249,49 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.33"
|
version = "1.0.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ref-cast"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f"
|
||||||
|
dependencies = [
|
||||||
|
"ref-cast-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ref-cast-impl"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust_decimal"
|
name = "rust_decimal"
|
||||||
version = "1.32.0"
|
version = "1.32.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd"
|
checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.7.4",
|
"arrayvec",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -318,20 +303,18 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schemars"
|
name = "schemars"
|
||||||
version = "0.8.21"
|
version = "1.0.0-alpha.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.5.2",
|
"arrayvec",
|
||||||
"arrayvec 0.7.4",
|
"bigdecimal",
|
||||||
"bigdecimal 0.3.1",
|
|
||||||
"bigdecimal 0.4.2",
|
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
"either",
|
"either",
|
||||||
"enumset",
|
"enumset",
|
||||||
"indexmap 1.9.3",
|
"indexmap",
|
||||||
"indexmap 2.0.2",
|
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
"ref-cast",
|
||||||
"rust_decimal",
|
"rust_decimal",
|
||||||
"schemars_derive",
|
"schemars_derive",
|
||||||
"semver",
|
"semver",
|
||||||
|
@ -341,13 +324,12 @@ dependencies = [
|
||||||
"smol_str",
|
"smol_str",
|
||||||
"trybuild",
|
"trybuild",
|
||||||
"url",
|
"url",
|
||||||
"uuid 0.8.2",
|
"uuid",
|
||||||
"uuid 1.5.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schemars_derive"
|
name = "schemars_derive"
|
||||||
version = "0.8.21"
|
version = "1.0.0-alpha.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -361,9 +343,6 @@ name = "semver"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
|
@ -402,6 +381,7 @@ version = "1.0.107"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
|
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -415,18 +395,15 @@ checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smol_str"
|
name = "smol_str"
|
||||||
version = "0.1.24"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9"
|
checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.38"
|
version = "2.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -504,12 +481,6 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "uuid"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
76
README.md
76
README.md
|
@ -1,12 +1,13 @@
|
||||||
# Schemars
|
# Schemars
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Schemars 1.0 is in development on [the v1 branch](https://github.com/GREsau/schemars/tree/v1), see [draft PR 290](https://github.com/GREsau/schemars/pull/290) for updates
|
> This branch is for the current v1 alpha version of Schemars which is still under development.
|
||||||
|
> For the current stable release of Schemars (v0.8.x), see the [v0 branch](https://github.com/GREsau/schemars/tree/v0).
|
||||||
|
|
||||||
[](https://github.com/GREsau/schemars/actions)
|
[](https://github.com/GREsau/schemars/actions)
|
||||||
[](https://crates.io/crates/schemars)
|
[](https://crates.io/crates/schemars)
|
||||||
[](https://docs.rs/schemars)
|
[](https://docs.rs/schemars)
|
||||||
[](https://blog.rust-lang.org/2022/04/07/Rust-1.60.0.html)
|
[](https://blog.rust-lang.org/2022/04/07/Rust-1.60.0.html)
|
||||||
|
|
||||||
Generate JSON Schema documents from Rust code
|
Generate JSON Schema documents from Rust code
|
||||||
|
|
||||||
|
@ -39,10 +40,9 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["my_bool", "my_int"],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -54,7 +54,7 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
"my_nullable_enum": {
|
"my_nullable_enum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
|
@ -62,26 +62,25 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"required": ["my_int", "my_bool"],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"anyOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["StringNewType"],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": ["StringNewType"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["StructVariant"],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["floats"],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -90,10 +89,12 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": ["floats"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": ["StructVariant"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -137,24 +138,23 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["myBool", "myNumber"],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"myBool": {
|
"myBool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"myNullableEnum": {
|
"myNullableEnum": {
|
||||||
"default": null,
|
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"default": null
|
||||||
},
|
},
|
||||||
"myNumber": {
|
"myNumber": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -162,7 +162,8 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"definitions": {
|
"required": ["myNumber", "myBool"],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
@ -170,7 +171,6 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["floats"],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -179,7 +179,8 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": ["floats"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -254,33 +255,28 @@ println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
## Feature Flags
|
## Feature Flags
|
||||||
|
|
||||||
- `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro
|
- `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro
|
||||||
- `impl_json_schema` - implements `JsonSchema` for Schemars types themselves
|
- `preserve_order` - keep the order of struct fields in `Schema` properties
|
||||||
- `preserve_order` - keep the order of struct fields in `Schema` and `SchemaObject`
|
|
||||||
- `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature)
|
- `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature)
|
||||||
|
|
||||||
Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets):
|
Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets):
|
||||||
|
|
||||||
- `chrono` - [chrono](https://crates.io/crates/chrono) (^0.4)
|
|
||||||
- `indexmap1` - [indexmap](https://crates.io/crates/indexmap) (^1.2)
|
|
||||||
- `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0)
|
|
||||||
- `either` - [either](https://crates.io/crates/either) (^1.3)
|
|
||||||
- `uuid08` - [uuid](https://crates.io/crates/uuid) (^0.8)
|
|
||||||
- `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0)
|
|
||||||
- `smallvec` - [smallvec](https://crates.io/crates/smallvec) (^1.0)
|
|
||||||
- `arrayvec05` - [arrayvec](https://crates.io/crates/arrayvec) (^0.5)
|
|
||||||
- `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7)
|
- `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7)
|
||||||
- `url` - [url](https://crates.io/crates/url) (^2.0)
|
|
||||||
- `bytes` - [bytes](https://crates.io/crates/bytes) (^1.0)
|
|
||||||
- `enumset` - [enumset](https://crates.io/crates/enumset) (^1.0)
|
|
||||||
- `rust_decimal` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0)
|
|
||||||
- `bigdecimal03` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.3)
|
|
||||||
- `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4)
|
- `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4)
|
||||||
- `smol_str` - [smol_str](https://crates.io/crates/smol_str) (^0.1.17)
|
- `bytes1` - [bytes](https://crates.io/crates/bytes) (^1.0)
|
||||||
- `semver` - [semver](https://crates.io/crates/semver) (^1.0.9)
|
- `chrono04` - [chrono](https://crates.io/crates/chrono) (^0.4)
|
||||||
|
- `either1` - [either](https://crates.io/crates/either) (^1.3)
|
||||||
|
- `enumset1` - [enumset](https://crates.io/crates/enumset) (^1.0)
|
||||||
|
- `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0)
|
||||||
|
- `rust_decimal1` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0)
|
||||||
|
- `semver1` - [semver](https://crates.io/crates/semver) (^1.0.9)
|
||||||
|
- `smallvec1` - [smallvec](https://crates.io/crates/smallvec) (^1.0)
|
||||||
|
- `smol_str02` - [smol_str](https://crates.io/crates/smol_str) (^0.2.1)
|
||||||
|
- `url2` - [url](https://crates.io/crates/url) (^2.0)
|
||||||
|
- `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0)
|
||||||
|
|
||||||
For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so:
|
For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
schemars = { version = "0.8", features = ["chrono"] }
|
schemars = { version = "1.0.0-alpha.3", features = ["chrono04"] }
|
||||||
```
|
```
|
||||||
|
|
175
docs/0-migrating.md
Normal file
175
docs/0-migrating.md
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
---
|
||||||
|
title: Migrating from 0.8
|
||||||
|
nav_order: 2
|
||||||
|
has_children: true
|
||||||
|
has_toc: false
|
||||||
|
permalink: /migrating/
|
||||||
|
layout: default
|
||||||
|
---
|
||||||
|
|
||||||
|
# Migrating from 0.8 to 1.0
|
||||||
|
|
||||||
|
<blockquote class="warning">
|
||||||
|
<p>Schemars 1.0 is still under development, and further changes may be introduced.
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
## Optional dependencies
|
||||||
|
|
||||||
|
All optional dependencies are now suffixed by their version:
|
||||||
|
|
||||||
|
- `chrono` is now `chrono04`
|
||||||
|
- `either` is now `either1`
|
||||||
|
- `smallvec` is now `smallvec1`
|
||||||
|
- `url` is now `url2`
|
||||||
|
- `bytes` is now `bytes1`
|
||||||
|
- `rust_decimal` is now `rust_decimal1`
|
||||||
|
- `enumset` is now `enumset1`
|
||||||
|
- `smol_str` is now `smol_str02`
|
||||||
|
- `semver` is now `semver1`
|
||||||
|
- `indexmap`, `uuid08`, `arrayvec05` and `bigdecimal03` have been removed
|
||||||
|
- `indexmap2`, `arrayvec07` and `bigdecimal04` are unchanged
|
||||||
|
|
||||||
|
## `Schema` is now a wrapper around `serde_json::Value`
|
||||||
|
|
||||||
|
`Schema` is now defined as a wrapper around a `serde_json::Value` (which must be a `Value::Bool` or `Value::Object`), rather than a struct with a field for each JSON schema keyword (with some intermediary types). `Schema` is now available as `schemars::Schema` instead of `schemars::schema::Schema`, and all other types that were in the `schemars::schema` module have now been removed. Functions that previously returned a `RootSchema` now just return a `Schema`.
|
||||||
|
|
||||||
|
A new macro `json_schema!(...)` is available to easily create new instances of `Schema`, which functions similarly to the [`serde_json::json!(...)` macro](https://docs.rs/serde_json/latest/serde_json/macro.json.html).
|
||||||
|
|
||||||
|
Here's how you might create and modify a `Schema` in schemars v0.8:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use schemars::schema::{InstanceType, ObjectValidation, Schema, SchemaObject};
|
||||||
|
use schemars::Map;
|
||||||
|
|
||||||
|
// Create a Schema for an object with property `foo`
|
||||||
|
let schema_object = SchemaObject {
|
||||||
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
|
object: Some(Box::new(ObjectValidation {
|
||||||
|
properties: Map::from_iter([("foo".to_owned(), true.into())]),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let schema: Schema = schema_object.into();
|
||||||
|
|
||||||
|
// Make the `foo` property required
|
||||||
|
let mut schema_object = schema.into_object();
|
||||||
|
let obj = schema_object.object();
|
||||||
|
obj.required.insert("foo".to_owned());
|
||||||
|
```
|
||||||
|
|
||||||
|
And the same thing in v1.0:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use schemars::{json_schema, Schema};
|
||||||
|
|
||||||
|
// Create a Schema for an object with property `foo`
|
||||||
|
let mut schema: Schema = json_schema!({
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"foo": true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make the `foo` property required
|
||||||
|
schema
|
||||||
|
.ensure_object()
|
||||||
|
.entry("required")
|
||||||
|
.or_insert(serde_json::Value::Array(Vec::new()))
|
||||||
|
.as_array_mut()
|
||||||
|
.expect("`required` should be an array")
|
||||||
|
.push("foo".into());
|
||||||
|
```
|
||||||
|
|
||||||
|
## `visit::Visitor` replaced with `transform::Transform`
|
||||||
|
|
||||||
|
The `visit` module and `Visitor` trait have been replace with `transform` and `Transform` respectively. Accordingly, these items have been renamed:
|
||||||
|
|
||||||
|
- `SchemaSettings::visitors` -> `SchemaSettings::transforms`
|
||||||
|
- `SchemaSettings::with_visitor` -> `SchemaSettings::with_transform`
|
||||||
|
- `SchemaGenerator::visitors_mut` -> `SchemaGenerator::transforms_mut`
|
||||||
|
- `GenVisitor` -> `GenTransform`
|
||||||
|
- `Visitor::visit_schema` -> `Transform::transform`
|
||||||
|
- `visit_schema_object` and `visit_root_schema` methods have been removed
|
||||||
|
- `visit::visit_schema` -> `transform::transform_subschemas`
|
||||||
|
- `visit_schema_object` and `visit_root_schema` functions have been removed
|
||||||
|
|
||||||
|
So if you had defined this `Visitor` in schemars 0.8:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use schemars::schema::SchemaObject;
|
||||||
|
use schemars::visit::{visit_schema_object, Visitor};
|
||||||
|
|
||||||
|
pub struct MyVisitor;
|
||||||
|
|
||||||
|
impl Visitor for MyVisitor {
|
||||||
|
fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
|
||||||
|
// First, make our change to this schema
|
||||||
|
schema
|
||||||
|
.extensions
|
||||||
|
.insert("my_property".to_string(), serde_json::json!("hello world"));
|
||||||
|
|
||||||
|
// Then delegate to default implementation to visit any subschemas
|
||||||
|
visit_schema_object(self, schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut schema = schemars::schema_for!(str);
|
||||||
|
MyVisitor.visit_root_schema(&mut schema);
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the equivalent `Transform` in schemars 1.0 would be:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use schemars::transform::{transform_subschemas, Transform};
|
||||||
|
use schemars::Schema;
|
||||||
|
|
||||||
|
pub struct MyTransform;
|
||||||
|
|
||||||
|
impl Transform for MyTransform {
|
||||||
|
fn transform(&mut self, schema: &mut Schema) {
|
||||||
|
// First, make our change to this schema
|
||||||
|
if let Some(obj) = schema.as_object_mut() {
|
||||||
|
obj.insert("my_property".to_string(), serde_json::json!("hello world"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then apply the transform to any subschemas
|
||||||
|
transform_subschemas(self, schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut schema = schemars::schema_for!(str);
|
||||||
|
MyTransform.transform(&mut schema);
|
||||||
|
```
|
||||||
|
|
||||||
|
Also, since `Transform` is now implemented for functions that take a single `&mut Schema` argument, you could also define it as a function instead of a struct:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn my_transform(schema: &mut Schema) {
|
||||||
|
// First, make our change to this schema
|
||||||
|
if let Some(obj) = schema.as_object_mut() {
|
||||||
|
obj.insert("my_property".to_string(), serde_json::json!("hello world"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then apply the transform to any subschemas
|
||||||
|
transform_subschemas(&mut my_transform, schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut schema = schemars::schema_for!(str);
|
||||||
|
my_transform(&mut schema);
|
||||||
|
// Or equivalently:
|
||||||
|
// my_transform.transform(&mut schema);
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, you can also use the `RecursiveTransform` newtype to convert a non-recursive `Transform` (i.e. one that does not transform subschemas) into a recursive one, like so:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn my_transform2(schema: &mut Schema) {
|
||||||
|
if let Some(obj) = schema.as_object_mut() {
|
||||||
|
obj.insert("my_property".to_string(), serde_json::json!("hello world"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut schema = schemars::schema_for!(str);
|
||||||
|
RecursiveTransform(my_transform2).transform(&mut schema);
|
||||||
|
```
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Deriving JsonSchema
|
title: Deriving JsonSchema
|
||||||
nav_order: 2
|
nav_order: 3
|
||||||
has_children: true
|
has_children: true
|
||||||
has_toc: false
|
has_toc: false
|
||||||
permalink: /deriving/
|
permalink: /deriving/
|
||||||
|
@ -12,6 +11,7 @@ permalink: /deriving/
|
||||||
The most important trait in Schemars is `JsonSchema`, and the most important function of that trait is `json_schema(...)` which returns a JSON schema describing the type. Implementing this manually on many types would be slow and error-prone, so Schemars includes a derive macro which can implement that trait for you. Any derived implementation of `JsonSchema` should create a schema that describes the JSON representation of the type if it were to be serialized by serde_json.
|
The most important trait in Schemars is `JsonSchema`, and the most important function of that trait is `json_schema(...)` which returns a JSON schema describing the type. Implementing this manually on many types would be slow and error-prone, so Schemars includes a derive macro which can implement that trait for you. Any derived implementation of `JsonSchema` should create a schema that describes the JSON representation of the type if it were to be serialized by serde_json.
|
||||||
|
|
||||||
Usually, all you need to do to use it is to add a `#[derive(JsonSchema)]` attribute to your type:
|
Usually, all you need to do to use it is to add a `#[derive(JsonSchema)]` attribute to your type:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use schemars::{JsonSchema, schema_for};
|
use schemars::{JsonSchema, schema_for};
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ fn main() {
|
||||||
println!("{}", serialized);
|
println!("{}", serialized);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
<!-- TODO:
|
|
||||||
|
<!-- TODO:
|
||||||
show example output
|
show example output
|
||||||
requirements - when can/can't it be derived
|
requirements - when can/can't it be derived
|
||||||
generic params behaviour
|
generic params behaviour
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Attributes
|
title: Attributes
|
||||||
parent: Deriving JsonSchema
|
parent: Deriving JsonSchema
|
||||||
nav_order: 1
|
nav_order: 1
|
||||||
|
@ -26,30 +25,33 @@ TABLE OF CONTENTS
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
1. [Supported Serde Attributes](#supported-serde-attributes)
|
1. [Supported Serde Attributes](#supported-serde-attributes)
|
||||||
- [`rename`](#rename)
|
- [`rename`](#rename)
|
||||||
- [`rename_all`](#rename_all)
|
- [`rename_all`](#rename_all)
|
||||||
- [`tag` / `content` / `untagged`](#tag)
|
- [`tag` / `content` / `untagged`](#tag)
|
||||||
- [`default`](#default)
|
- [`default`](#default)
|
||||||
- [`skip`](#skip)
|
- [`skip`](#skip)
|
||||||
- [`skip_serializing`](#skip_serializing)
|
- [`skip_serializing`](#skip_serializing)
|
||||||
- [`skip_deserializing`](#skip_deserializing)
|
- [`skip_deserializing`](#skip_deserializing)
|
||||||
- [`flatten`](#flatten)
|
- [`flatten`](#flatten)
|
||||||
- [`with`](#with)
|
- [`with`](#with)
|
||||||
- [`bound`](#bound)
|
- [`bound`](#bound)
|
||||||
1. [Supported Validator Attributes](#supported-validator-attributes)
|
1. [Supported Validator Attributes](#supported-validator-attributes)
|
||||||
- [`email` / `phone` / `url`](#email-phone-url)
|
- [`email` / `phone` / `url`](#email-phone-url)
|
||||||
- [`length`](#length)
|
- [`length`](#length)
|
||||||
- [`range`](#range)
|
- [`range`](#range)
|
||||||
- [`regex`](#regex)
|
- [`regex`](#regex)
|
||||||
- [`contains`](#contains)
|
- [`contains`](#contains)
|
||||||
- [`required` / `required_nested`](#required)
|
- [`required` / `required_nested`](#required)
|
||||||
1. [Other Attributes](#other-attributes)
|
1. [Other Attributes](#other-attributes)
|
||||||
- [`schema_with`](#schema_with)
|
- [`schema_with`](#schema_with)
|
||||||
- [`title` / `description`](#title-description)
|
- [`title` / `description`](#title-description)
|
||||||
- [`example`](#example)
|
- [`example`](#example)
|
||||||
- [`deprecated`](#deprecated)
|
- [`deprecated`](#deprecated)
|
||||||
- [`crate`](#crate)
|
- [`crate`](#crate)
|
||||||
- [Doc Comments (`doc`)](#doc)
|
- [`extend`](#extend)
|
||||||
|
- [`transform`](#transform)
|
||||||
|
- [Doc Comments (`doc`)](#doc)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Supported Serde Attributes
|
## Supported Serde Attributes
|
||||||
|
@ -59,9 +61,10 @@ TABLE OF CONTENTS
|
||||||
<h3 id="rename">
|
<h3 id="rename">
|
||||||
|
|
||||||
`#[serde(rename = "name")]` / `#[schemars(rename = "name")]`
|
`#[serde(rename = "name")]` / `#[schemars(rename = "name")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a struct, enum, field or variant to use the given name in the generated schema instead of the Rust name. When used on a struct or enum, the given name will be used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
|
Set on a struct, enum, field or variant to use the given name in the generated schema instead of the Rust name. When used on a struct or enum, the given name will be used as the title for root schemas, and the key within the root's `$defs` property for subschemas.
|
||||||
|
|
||||||
If set on a struct or enum with generic type parameters, then the given name may contain them enclosed in curly braces (e.g. `{T}`) and they will be replaced with the concrete type names when the schema is generated.
|
If set on a struct or enum with generic type parameters, then the given name may contain them enclosed in curly braces (e.g. `{T}`) and they will be replaced with the concrete type names when the schema is generated.
|
||||||
|
|
||||||
|
@ -70,6 +73,7 @@ Serde docs: [container](https://serde.rs/container-attrs.html#rename) / [variant
|
||||||
<h3 id="rename_all">
|
<h3 id="rename_all">
|
||||||
|
|
||||||
`#[serde(rename_all = "...")]` / `#[schemars(rename_all = "...")]`
|
`#[serde(rename_all = "...")]` / `#[schemars(rename_all = "...")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a struct, enum or variant to rename all fields according to the given case convention (see the Serde docs for details).
|
Set on a struct, enum or variant to rename all fields according to the given case convention (see the Serde docs for details).
|
||||||
|
@ -81,6 +85,7 @@ Serde docs: [container](https://serde.rs/container-attrs.html#rename_all) / [var
|
||||||
`#[serde(tag = "type")]` / `#[schemars(tag = "type")]` <br />
|
`#[serde(tag = "type")]` / `#[schemars(tag = "type")]` <br />
|
||||||
`#[serde(tag = "t", content = "c")]` / `#[schemars(tag = "t", content = "c")]` <br />
|
`#[serde(tag = "t", content = "c")]` / `#[schemars(tag = "t", content = "c")]` <br />
|
||||||
`#[serde(untagged)]` / `#[schemars(untagged)]`
|
`#[serde(untagged)]` / `#[schemars(untagged)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on an enum to generate the schema for the [internally tagged](https://serde.rs/enum-representations.html#internally-tagged), [adjacently tagged](https://serde.rs/enum-representations.html#adjacently-tagged), or [untagged](https://serde.rs/enum-representations.html#untagged) representation of this enum.
|
Set on an enum to generate the schema for the [internally tagged](https://serde.rs/enum-representations.html#internally-tagged), [adjacently tagged](https://serde.rs/enum-representations.html#adjacently-tagged), or [untagged](https://serde.rs/enum-representations.html#untagged) representation of this enum.
|
||||||
|
@ -90,6 +95,7 @@ Serde docs: [`tag`](https://serde.rs/container-attrs.html#tag) / [`tag`+`content
|
||||||
<h3 id="default">
|
<h3 id="default">
|
||||||
|
|
||||||
`#[serde(default)]` / `#[schemars(default)]` / `#[serde(default = "path")]` / `#[schemars(default = "path")]`
|
`#[serde(default)]` / `#[schemars(default)]` / `#[serde(default = "path")]` / `#[schemars(default = "path")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a struct or field to give fields a default value, which excludes them from the schema's `required` properties. The default will also be set on the field's schema's `default` property, unless it is skipped by a [`skip_serializing_if`](https://serde.rs/field-attrs.html#skip_serializing_if) attribute on the field. Any [`serialize_with`](https://serde.rs/field-attrs.html#serialize_with) or [`with`](https://serde.rs/field-attrs.html#with) attribute set on the field will be used to serialize the default value.
|
Set on a struct or field to give fields a default value, which excludes them from the schema's `required` properties. The default will also be set on the field's schema's `default` property, unless it is skipped by a [`skip_serializing_if`](https://serde.rs/field-attrs.html#skip_serializing_if) attribute on the field. Any [`serialize_with`](https://serde.rs/field-attrs.html#serialize_with) or [`with`](https://serde.rs/field-attrs.html#with) attribute set on the field will be used to serialize the default value.
|
||||||
|
@ -99,6 +105,7 @@ Serde docs: [container](https://serde.rs/container-attrs.html#default) / [field]
|
||||||
<h3 id="skip">
|
<h3 id="skip">
|
||||||
|
|
||||||
`#[serde(skip)]` / `#[schemars(skip)]`
|
`#[serde(skip)]` / `#[schemars(skip)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a variant or field to prevent it from appearing in any generated schema.
|
Set on a variant or field to prevent it from appearing in any generated schema.
|
||||||
|
@ -108,6 +115,7 @@ Serde docs: [variant](https://serde.rs/variant-attrs.html#skip) / [field](https:
|
||||||
<h3 id="skip_serializing">
|
<h3 id="skip_serializing">
|
||||||
|
|
||||||
`#[serde(skip_serializing)]` / `#[schemars(skip_serializing)]`
|
`#[serde(skip_serializing)]` / `#[schemars(skip_serializing)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a field of a (non-tuple) struct to set the `writeOnly` property on that field's schema. Serde also allows this attribute on variants or tuple struct fields, but this will have no effect on generated schemas.
|
Set on a field of a (non-tuple) struct to set the `writeOnly` property on that field's schema. Serde also allows this attribute on variants or tuple struct fields, but this will have no effect on generated schemas.
|
||||||
|
@ -117,6 +125,7 @@ Serde docs: [field](https://serde.rs/field-attrs.html#skip_deserializing)
|
||||||
<h3 id="skip_deserializing">
|
<h3 id="skip_deserializing">
|
||||||
|
|
||||||
`#[serde(skip_deserializing)]` / `#[schemars(skip_deserializing)]`
|
`#[serde(skip_deserializing)]` / `#[schemars(skip_deserializing)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a variant or field. When set on a field of a (non-tuple) struct, that field's schema will have the `readOnly` property set. When set on a variant or tuple struct field Schemars will treat this the same as a [`skip`](#skip) attribute.
|
Set on a variant or field. When set on a field of a (non-tuple) struct, that field's schema will have the `readOnly` property set. When set on a variant or tuple struct field Schemars will treat this the same as a [`skip`](#skip) attribute.
|
||||||
|
@ -126,6 +135,7 @@ Serde docs: [variant](https://serde.rs/variant-attrs.html#skip_deserializing) /
|
||||||
<h3 id="flatten">
|
<h3 id="flatten">
|
||||||
|
|
||||||
`#[serde(flatten)]` / `#[schemars(flatten)]`
|
`#[serde(flatten)]` / `#[schemars(flatten)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a field to include that field's contents as though they belonged to the field's container.
|
Set on a field to include that field's contents as though they belonged to the field's container.
|
||||||
|
@ -135,6 +145,7 @@ Serde docs: [field](https://serde.rs/field-attrs.html#flatten)
|
||||||
<h3 id="with">
|
<h3 id="with">
|
||||||
|
|
||||||
`#[serde(with = "Type")]` / `#[schemars(with = "Type")]`
|
`#[serde(with = "Type")]` / `#[schemars(with = "Type")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a variant or field to generate its schema as the given type instead of its actual type. Serde allows the `with` attribute to refer to any module path, but Schemars requires this to be an actual type which implements `JsonSchema`.
|
Set on a variant or field to generate its schema as the given type instead of its actual type. Serde allows the `with` attribute to refer to any module path, but Schemars requires this to be an actual type which implements `JsonSchema`.
|
||||||
|
@ -146,6 +157,7 @@ Serde docs: [variant](https://serde.rs/variant-attrs.html#with) / [field](https:
|
||||||
<h3 id="deny_unknown_fields">
|
<h3 id="deny_unknown_fields">
|
||||||
|
|
||||||
`#[serde(deny_unknown_fields)]` / `#[schemars(deny_unknown_fields)]`
|
`#[serde(deny_unknown_fields)]` / `#[schemars(deny_unknown_fields)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Setting this on a container will set the `additionalProperties` keyword on generated schemas to `false` to show that any extra properties are explicitly disallowed.
|
Setting this on a container will set the `additionalProperties` keyword on generated schemas to `false` to show that any extra properties are explicitly disallowed.
|
||||||
|
@ -155,6 +167,7 @@ Serde docs: [container](https://serde.rs/container-attrs.html#deny_unknown_field
|
||||||
<h3 id="transparent">
|
<h3 id="transparent">
|
||||||
|
|
||||||
`#[serde(transparent)]` / `#[schemars(transparent)]`
|
`#[serde(transparent)]` / `#[schemars(transparent)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a newtype struct or a braced struct with one field to make the struct's generated schema exactly the same as that of the single field's.
|
Set on a newtype struct or a braced struct with one field to make the struct's generated schema exactly the same as that of the single field's.
|
||||||
|
@ -164,6 +177,7 @@ Serde docs: [container](https://serde.rs/container-attrs.html#transparent)
|
||||||
<h3 id="bound">
|
<h3 id="bound">
|
||||||
|
|
||||||
`#[schemars(bound = "...")]`
|
`#[schemars(bound = "...")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Where-clause for the JsonSchema impl. This replaces any trait bounds inferred by schemars. Schemars does **not** use trait bounds from `#[serde(bound)]` attributes.
|
Where-clause for the JsonSchema impl. This replaces any trait bounds inferred by schemars. Schemars does **not** use trait bounds from `#[serde(bound)]` attributes.
|
||||||
|
@ -181,6 +195,7 @@ Serde docs: [container](https://serde.rs/container-attrs.html#bound)
|
||||||
`#[validate(email)]` / `#[schemars(email)]`<br />
|
`#[validate(email)]` / `#[schemars(email)]`<br />
|
||||||
`#[validate(phone)]` / `#[schemars(phone)]`<br />
|
`#[validate(phone)]` / `#[schemars(phone)]`<br />
|
||||||
`#[validate(url)]` / `#[schemars(url)]`
|
`#[validate(url)]` / `#[schemars(url)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Sets the schema's `format` to `email`/`phone`/`uri`, as appropriate. Only one of these attributes may be present on a single field.
|
Sets the schema's `format` to `email`/`phone`/`uri`, as appropriate. Only one of these attributes may be present on a single field.
|
||||||
|
@ -191,6 +206,7 @@ Validator docs: [email](https://github.com/Keats/validator#email) / [phone](http
|
||||||
|
|
||||||
`#[validate(length(min = 1, max = 10))]` / `#[schemars(length(min = 1, max = 10))]`<br />
|
`#[validate(length(min = 1, max = 10))]` / `#[schemars(length(min = 1, max = 10))]`<br />
|
||||||
`#[validate(length(equal = 10))]` / `#[schemars(length(equal = 10))]`
|
`#[validate(length(equal = 10))]` / `#[schemars(length(equal = 10))]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Sets the `minLength`/`maxLength` properties for string schemas, or the `minItems`/`maxItems` properties for array schemas.
|
Sets the `minLength`/`maxLength` properties for string schemas, or the `minItems`/`maxItems` properties for array schemas.
|
||||||
|
@ -200,6 +216,7 @@ Validator docs: [length](https://github.com/Keats/validator#length)
|
||||||
<h3 id="range">
|
<h3 id="range">
|
||||||
|
|
||||||
`#[validate(range(min = 1, max = 10))]` / `#[schemars(range(min = 1, max = 10))]`
|
`#[validate(range(min = 1, max = 10))]` / `#[schemars(range(min = 1, max = 10))]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Sets the `minimum`/`maximum` properties for number schemas.
|
Sets the `minimum`/`maximum` properties for number schemas.
|
||||||
|
@ -210,6 +227,7 @@ Validator docs: [range](https://github.com/Keats/validator#range)
|
||||||
|
|
||||||
`#[validate(regex = "path::to::regex")]` / `#[schemars(regex = "path::to::regex")]`<br />
|
`#[validate(regex = "path::to::regex")]` / `#[schemars(regex = "path::to::regex")]`<br />
|
||||||
`#[schemars(regex(pattern = r"^\d+$"))]`
|
`#[schemars(regex(pattern = r"^\d+$"))]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Sets the `pattern` property for string schemas. The `path::to::regex` will typically refer to a [`Regex`](https://docs.rs/regex/*/regex/struct.Regex.html) instance, but Schemars allows it to be any value with a `to_string()` method.
|
Sets the `pattern` property for string schemas. The `path::to::regex` will typically refer to a [`Regex`](https://docs.rs/regex/*/regex/struct.Regex.html) instance, but Schemars allows it to be any value with a `to_string()` method.
|
||||||
|
@ -221,6 +239,7 @@ Validator docs: [regex](https://github.com/Keats/validator#regex)
|
||||||
<h3 id="contains">
|
<h3 id="contains">
|
||||||
|
|
||||||
`#[validate(contains = "string")]` / `#[schemars(contains = "string")]`
|
`#[validate(contains = "string")]` / `#[schemars(contains = "string")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
For string schemas, sets the `pattern` property to the given value, with any regex special characters escaped. For object schemas (e.g. when the attribute is set on a HashMap field), includes the value in the `required` property, indicating that the map must contain it as a key.
|
For string schemas, sets the `pattern` property to the given value, with any regex special characters escaped. For object schemas (e.g. when the attribute is set on a HashMap field), includes the value in the `required` property, indicating that the map must contain it as a key.
|
||||||
|
@ -231,6 +250,7 @@ Validator docs: [contains](https://github.com/Keats/validator#contains)
|
||||||
|
|
||||||
`#[validate(required)]` / `#[schemars(required)]`<br />
|
`#[validate(required)]` / `#[schemars(required)]`<br />
|
||||||
`#[validate(required_nested)]`
|
`#[validate(required_nested)]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
When set on an `Option<T>` field, this will create a schemas as though the field were a `T`.
|
When set on an `Option<T>` field, this will create a schemas as though the field were a `T`.
|
||||||
|
@ -244,6 +264,7 @@ Validator docs: [required](https://github.com/Keats/validator#required) / [requi
|
||||||
<h3 id="schema_with">
|
<h3 id="schema_with">
|
||||||
|
|
||||||
`#[schemars(schema_with = "some::function")]`
|
`#[schemars(schema_with = "some::function")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a variant or field to generate this field's schema using the given function. This function must be callable as `fn(&mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema`.
|
Set on a variant or field to generate this field's schema using the given function. This function must be callable as `fn(&mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema`.
|
||||||
|
@ -251,6 +272,7 @@ Set on a variant or field to generate this field's schema using the given functi
|
||||||
<h3 id="title-description">
|
<h3 id="title-description">
|
||||||
|
|
||||||
`#[schemars(title = "Some title", description = "Some description")]`
|
`#[schemars(title = "Some title", description = "Some description")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a container, variant or field to set the generated schema's `title` and/or `description`. If present, these will be used instead of values from any [`doc` comments/attributes](#doc).
|
Set on a container, variant or field to set the generated schema's `title` and/or `description`. If present, these will be used instead of values from any [`doc` comments/attributes](#doc).
|
||||||
|
@ -258,6 +280,7 @@ Set on a container, variant or field to set the generated schema's `title` and/o
|
||||||
<h3 id="example">
|
<h3 id="example">
|
||||||
|
|
||||||
`#[schemars(example = "some::function")]`
|
`#[schemars(example = "some::function")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set on a container, variant or field to include the result of the given function in the generated schema's `examples`. The function should take no parameters and can return any type that implements serde's `Serialize` trait - it does not need to return the same type as the attached struct/field. This attribute can be repeated to specify multiple examples.
|
Set on a container, variant or field to include the result of the given function in the generated schema's `examples`. The function should take no parameters and can return any type that implements serde's `Serialize` trait - it does not need to return the same type as the attached struct/field. This attribute can be repeated to specify multiple examples.
|
||||||
|
@ -265,6 +288,7 @@ Set on a container, variant or field to include the result of the given function
|
||||||
<h3 id="deprecated">
|
<h3 id="deprecated">
|
||||||
|
|
||||||
`#[deprecated]`
|
`#[deprecated]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set the Rust built-in [`deprecated`](https://doc.rust-lang.org/edition-guide/rust-2018/the-compiler/an-attribute-for-deprecation.html) attribute on a struct, enum, field or variant to set the generated schema's `deprecated` keyword to `true`.
|
Set the Rust built-in [`deprecated`](https://doc.rust-lang.org/edition-guide/rust-2018/the-compiler/an-attribute-for-deprecation.html) attribute on a struct, enum, field or variant to set the generated schema's `deprecated` keyword to `true`.
|
||||||
|
@ -272,6 +296,7 @@ Set the Rust built-in [`deprecated`](https://doc.rust-lang.org/edition-guide/rus
|
||||||
<h3 id="crate">
|
<h3 id="crate">
|
||||||
|
|
||||||
`#[schemars(crate = "other_crate::schemars")]`
|
`#[schemars(crate = "other_crate::schemars")]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Set the path to the schemars crate instance the generated code should depend on. This is mostly useful for other crates that depend on schemars in their macros.
|
Set the path to the schemars crate instance the generated code should depend on. This is mostly useful for other crates that depend on schemars in their macros.
|
||||||
|
@ -279,6 +304,7 @@ Set the path to the schemars crate instance the generated code should depend on.
|
||||||
<h3 id="inner">
|
<h3 id="inner">
|
||||||
|
|
||||||
`#[schemars(inner(...))]`
|
`#[schemars(inner(...))]`
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
Sets properties specified by [validator attributes](#supported-validator-attributes) on items of an array schema. For example:
|
Sets properties specified by [validator attributes](#supported-validator-attributes) on items of an array schema. For example:
|
||||||
|
@ -290,9 +316,46 @@ struct Struct {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<h3 id="extend">
|
||||||
|
|
||||||
|
`#[schemars(extend("key" = value))]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a container, variant or field to add properties (or replace existing properties) in a generated schema. This can contain multiple key/value pairs and/or be specified multiple times, as long as each key is unique.
|
||||||
|
|
||||||
|
The key must be a quoted string, and the value can be any expression that produces a type implementing `serde::Serialize`. The value can also be a JSON literal which can interpolate other values.
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
#[schemars(extend("simple" = "string value", "complex" = {"array": [1, 2, 3]}))]
|
||||||
|
struct Struct;
|
||||||
|
```
|
||||||
|
|
||||||
|
<h3 id="transform">
|
||||||
|
|
||||||
|
`#[schemars(transform = some::transform)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a container, variant or field to run a `schemars::transform::Transform` against the generated schema. This can be specified multiple times to run multiple transforms.
|
||||||
|
|
||||||
|
The `Transform` trait is implemented on functions with the signature `fn(&mut Schema) -> ()`, allowing you to do this:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn my_transform(schema: &mut Schema) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
#[schemars(transform = my_transform)]
|
||||||
|
struct Struct;
|
||||||
|
```
|
||||||
|
|
||||||
<h3 id="doc">
|
<h3 id="doc">
|
||||||
|
|
||||||
Doc Comments (`#[doc = "..."]`)
|
Doc Comments (`#[doc = "..."]`)
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
If a struct, variant or field has any [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html#doc-comments) (or [`doc` attributes](https://doc.rust-lang.org/rustdoc/the-doc-attribute.html)), then these will be used as the generated schema's `description`. If the first line is an ATX-style markdown heading (i.e. it begins with a # character), then it will be used as the schema's `title`, and the remaining lines will be the `description`.
|
If a struct, variant or field has any [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html#doc-comments) (or [`doc` attributes](https://doc.rust-lang.org/rustdoc/the-doc-attribute.html)), then these will be used as the generated schema's `description`. If the first line is an ATX-style markdown heading (i.e. it begins with a # character), then it will be used as the schema's `title`, and the remaining lines will be the `description`.
|
||||||
|
|
|
@ -1,25 +1,22 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Implementing JsonSchema
|
title: Implementing JsonSchema
|
||||||
nav_order: 3
|
nav_order: 4
|
||||||
permalink: /implementing/
|
permalink: /implementing/
|
||||||
---
|
---
|
||||||
|
|
||||||
# Implementing JsonSchema
|
# Implementing JsonSchema
|
||||||
|
|
||||||
[Deriving `JsonSchema`]({{ site.baseurl }}{% link 1-deriving.md %}) is usually the easiest way to enable JSON schema generation for your types. But if you need more customisation, you can also implement `JsonSchema` manually. This trait has two associated functions which must be implemented, and one which can optionally be implemented:
|
[Deriving `JsonSchema`]({{ site.baseurl }}{% link 1-deriving.md %}) is usually the easiest way to enable JSON schema generation for your types. But if you need more customisation, you can also implement `JsonSchema` manually. This trait has two associated functions which must be implemented, one which usually _should_ be implemented, and one which can optionally be implemented:
|
||||||
|
|
||||||
## schema_name
|
## schema_name
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn schema_name() -> String;
|
fn schema_name() -> Cow<'static, str>;
|
||||||
```
|
```
|
||||||
|
|
||||||
This function returns the human-readable friendly name of the type's schema, which frequently is just the name of the type itself. The schema name is used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
|
This function returns the human-readable friendly name of the type's schema, which frequently is just the name of the type itself. The schema name is used as the title for root schemas, and the key within the root's `$defs` property for subschemas.
|
||||||
|
|
||||||
NB in a future version of schemars, it's likely that this function will be changed to return a `Cow<'static, str>`.
|
## schema_id (optional but recommended)
|
||||||
|
|
||||||
## schema_id
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn schema_id() -> Cow<'static, str>;
|
fn schema_id() -> Cow<'static, str>;
|
||||||
|
@ -29,8 +26,7 @@ This function returns a unique identifier of the type's schema - if two types re
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn schema_id() -> Cow<'static, str> {
|
fn schema_id() -> Cow<'static, str> {
|
||||||
Cow::Owned(
|
format!("[{}]", T::schema_id()).into()
|
||||||
format!("[{}]", T::schema_id()))
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -40,40 +36,45 @@ For a type with no generic type arguments, a reasonable implementation of this f
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
impl JsonSchema for NonGenericType {
|
impl JsonSchema for NonGenericType {
|
||||||
fn schema_name() -> String {
|
fn schema_name() -> Cow<'static, str> {
|
||||||
// Exclude the module path to make the name in generated schemas clearer.
|
// Exclude the module path to make the name in generated schemas clearer.
|
||||||
"NonGenericType".to_owned()
|
"NonGenericType".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema_id() -> Cow<'static, str> {
|
fn schema_id() -> Cow<'static, str> {
|
||||||
// Include the module, in case a type with the same name is in another module/crate
|
// Include the module, in case a type with the same name is in another module/crate
|
||||||
Cow::Borrowed(concat!(module_path!(), "::NonGenericType"))
|
concat!(module_path!(), "::NonGenericType").into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
|
||||||
todo!()
|
json_schema!({
|
||||||
|
"type": "object",
|
||||||
|
"foo": "bar"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The default implementation of this function returns `Self::schema_name()`.
|
||||||
|
|
||||||
## json_schema
|
## json_schema
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn json_schema(gen: &mut gen::SchemaGenerator) -> Schema;
|
fn json_schema(gen: &mut gen::SchemaGenerator) -> Schema;
|
||||||
```
|
```
|
||||||
|
|
||||||
This function creates the JSON schema itself. The `gen` argument can be used to check the schema generation settings, or to get schemas for other types. If you do need schemas for other types, you should call the `gen.subschema_for::<T>()` method instead of `<T>::json_schema(gen)`, as `subschema_for` can add `T`'s schema to the root schema's `definitions` so that it does not need to be duplicated when used more than once.
|
This function creates the JSON schema itself. The `gen` argument can be used to check the schema generation settings, or to get schemas for other types. If you do need schemas for other types, you should call the `gen.subschema_for::<T>()` method instead of `<T>::json_schema(gen)`, as `subschema_for` can add `T`'s schema to the root schema's `$defs` so that it does not need to be duplicated when used more than once.
|
||||||
|
|
||||||
`json_schema` should not return a `$ref` schema.
|
`json_schema` should not return a `$ref` schema.
|
||||||
|
|
||||||
## is_referenceable (optional)
|
## always_inline_schema (optional)
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn is_referenceable() -> bool;
|
fn always_inline_schema() -> bool;
|
||||||
```
|
```
|
||||||
|
|
||||||
If this function returns `true`, then Schemars can re-use the generate schema where possible by adding it to the root schema's `definitions` and having other schemas reference it using the `$ref` keyword. This can greatly simplify schemas that include a particular type multiple times, especially if that type's schema is fairly complex.
|
If this function returns `false`, then Schemars can re-use the generate schema where possible by adding it to the root schema's `$defs` and having other schemas reference it using the `$ref` keyword. This can greatly simplify schemas that include a particular type multiple times, especially if that type's schema is fairly complex.
|
||||||
|
|
||||||
Generally, this should return `false` for types with simple schemas (such as primitives). For more complex types, it should return `true`. For recursive types, this **must** return `true` to prevent infinite cycles when generating schemas.
|
Generally, this should return `true` for types with simple schemas (such as primitives). For more complex types, it should return `false`. For recursive types, this **must** return `false` to prevent infinite cycles when generating schemas.
|
||||||
|
|
||||||
The default implementation of this function returns `true` to reduce the chance of someone inadvertently causing infinite cycles with recursive types.
|
The default implementation of this function returns `false` to reduce the chance of someone inadvertently causing infinite cycles with recursive types.
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Generating Schemas
|
title: Generating Schemas
|
||||||
nav_order: 4
|
nav_order: 5
|
||||||
permalink: /generating/
|
permalink: /generating/
|
||||||
---
|
---
|
||||||
|
|
||||||
# Generating Schemas
|
# Generating Schemas
|
||||||
|
|
||||||
The easiest way to generate a schema for a type that implements is to use the [`schema_for!` macro](https://docs.rs/schemars/latest/schemars/macro.schema_for.html), like so:
|
The easiest way to generate a schema for a type that implements is to use the [`schema_for!` macro](https://docs.rs/schemars/latest/schemars/macro.schema_for.html), like so:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let my_schema = schema_for!(MyStruct);
|
let my_schema = schema_for!(MyStruct);
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a schema that conforms to [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
This will create a schema that conforms to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
||||||
|
|
||||||
If you want more control over how the schema is generated, you can use the [`gen` module](https://docs.rs/schemars/latest/schemars/gen/). There are two main types in this module:
|
If you want more control over how the schema is generated, you can use the [`gen` module](https://docs.rs/schemars/latest/schemars/gen/). There are two main types in this module:
|
||||||
* [`SchemaSettings`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaSettings.html), which defines what JSON Schema features should be used when generating schemas (for example, how `Option`s should be represented).
|
|
||||||
* [`SchemaGenerator`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaGenerator.html), which manages the generation of a schema document.
|
- [`SchemaSettings`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaSettings.html), which defines what JSON Schema features should be used when generating schemas (for example, how `Option`s should be represented).
|
||||||
|
- [`SchemaGenerator`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaGenerator.html), which manages the generation of a schema document.
|
||||||
|
|
||||||
|
For example, to generate a schema that conforms to [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7):
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let generator = SchemaSettings::draft07().into_generator();
|
||||||
|
let my_schema = generator.into_root_schema_for::<MyStruct>();
|
||||||
|
```
|
||||||
|
|
||||||
See the API documentation for more info on how to use those types for custom schema generation.
|
See the API documentation for more info on how to use those types for custom schema generation.
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,34 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Feature Flags
|
title: Feature Flags
|
||||||
nav_order: 5
|
nav_order: 6
|
||||||
permalink: /features/
|
permalink: /features/
|
||||||
---
|
---
|
||||||
|
|
||||||
# Feature Flags and Optional Dependencies
|
# Feature Flags and Optional Dependencies
|
||||||
|
|
||||||
- `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro
|
- `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro
|
||||||
- `impl_json_schema` - implements `JsonSchema` for Schemars types themselves
|
- `preserve_order` - keep the order of struct fields in `Schema` properties
|
||||||
- `preserve_order` - keep the order of struct fields in `Schema` and `SchemaObject`
|
|
||||||
- `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature)
|
- `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature)
|
||||||
|
|
||||||
Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets):
|
Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets):
|
||||||
|
|
||||||
- `chrono` - [chrono](https://crates.io/crates/chrono) (^0.4)
|
|
||||||
- `indexmap1` - [indexmap](https://crates.io/crates/indexmap) (^1.2)
|
|
||||||
- `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0)
|
|
||||||
- `either` - [either](https://crates.io/crates/either) (^1.3)
|
|
||||||
- `uuid08` - [uuid](https://crates.io/crates/uuid) (^0.8)
|
|
||||||
- `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0)
|
|
||||||
- `smallvec` - [smallvec](https://crates.io/crates/smallvec) (^1.0)
|
|
||||||
- `arrayvec05` - [arrayvec](https://crates.io/crates/arrayvec) (^0.5)
|
|
||||||
- `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7)
|
- `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7)
|
||||||
- `url` - [url](https://crates.io/crates/url) (^2.0)
|
|
||||||
- `bytes` - [bytes](https://crates.io/crates/bytes) (^1.0)
|
|
||||||
- `enumset` - [enumset](https://crates.io/crates/enumset) (^1.0)
|
|
||||||
- `rust_decimal` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0)
|
|
||||||
- `bigdecimal03` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.3)
|
|
||||||
- `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4)
|
- `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4)
|
||||||
- `smol_str` - [smol_str](https://crates.io/crates/smol_str) (^0.1.17)
|
- `bytes1` - [bytes](https://crates.io/crates/bytes) (^1.0)
|
||||||
- `semver` - [semver](https://crates.io/crates/semver) (^1.0.9)
|
- `chrono04` - [chrono](https://crates.io/crates/chrono) (^0.4)
|
||||||
|
- `either1` - [either](https://crates.io/crates/either) (^1.3)
|
||||||
|
- `enumset1` - [enumset](https://crates.io/crates/enumset) (^1.0)
|
||||||
|
- `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0)
|
||||||
|
- `rust_decimal1` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0)
|
||||||
|
- `semver1` - [semver](https://crates.io/crates/semver) (^1.0.9)
|
||||||
|
- `smallvec1` - [smallvec](https://crates.io/crates/smallvec) (^1.0)
|
||||||
|
- `smol_str02` - [smol_str](https://crates.io/crates/smol_str) (^0.2.1)
|
||||||
|
- `url2` - [url](https://crates.io/crates/url) (^2.0)
|
||||||
|
- `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0)
|
||||||
|
|
||||||
For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so:
|
For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
schemars = { version = "0.8", features = ["chrono"] }
|
schemars = { version = "1.0.0-alpha.3", features = ["chrono04"] }
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Examples
|
title: Examples
|
||||||
nav_order: 6
|
nav_order: 7
|
||||||
has_children: true
|
has_children: true
|
||||||
permalink: /examples/
|
permalink: /examples/
|
||||||
---
|
---
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
14
docs/Dockerfile
Normal file
14
docs/Dockerfile
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
FROM ruby:2.7.4
|
||||||
|
|
||||||
|
EXPOSE 4000
|
||||||
|
|
||||||
|
RUN gem update --system 3.4.22 && echo 'url: "http://localhost:4000"' > /_config.localhost.yml
|
||||||
|
|
||||||
|
COPY Gemfile .
|
||||||
|
|
||||||
|
RUN bundle install
|
||||||
|
|
||||||
|
ENV JEKYLL_ENV=docker
|
||||||
|
|
||||||
|
ENTRYPOINT [ "bundle", "exec", "jekyll"]
|
||||||
|
CMD [ "serve", "--force_polling", "--host", "0.0.0.0", "--config", "./_config.yml,/_config.localhost.yml" ]
|
|
@ -10,7 +10,7 @@ source "https://rubygems.org"
|
||||||
# gem "jekyll", "~> 4.0.0"
|
# gem "jekyll", "~> 4.0.0"
|
||||||
# This is the default theme for new Jekyll sites. You may change this to anything you like.
|
# This is the default theme for new Jekyll sites. You may change this to anything you like.
|
||||||
# gem "minima", "~> 2.5"
|
# gem "minima", "~> 2.5"
|
||||||
gem "just-the-docs", "= 0.3.2"
|
gem "just-the-docs", "= 0.8.2"
|
||||||
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
|
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
|
||||||
# uncomment the line below. To upgrade, run `bundle update github-pages`.
|
# uncomment the line below. To upgrade, run `bundle update github-pages`.
|
||||||
gem "github-pages", group: :jekyll_plugins
|
gem "github-pages", group: :jekyll_plugins
|
||||||
|
@ -24,7 +24,3 @@ install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do
|
||||||
gem "tzinfo", "~> 1.2"
|
gem "tzinfo", "~> 1.2"
|
||||||
gem "tzinfo-data"
|
gem "tzinfo-data"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Performance-booster for watching directories on Windows
|
|
||||||
gem "wdm", "~> 0.1.1", :install_if => Gem.win_platform?
|
|
||||||
|
|
||||||
|
|
|
@ -27,20 +27,47 @@ url: "https://graham.cool" # the base hostname & protocol for your site, e.g. ht
|
||||||
permalink: pretty
|
permalink: pretty
|
||||||
|
|
||||||
# Build settings
|
# Build settings
|
||||||
remote_theme: pmarsceill/just-the-docs@v0.3.2
|
remote_theme: pmarsceill/just-the-docs@v0.8.2
|
||||||
markdown: CommonMarkGhPages
|
markdown: CommonMarkGhPages
|
||||||
commonmark:
|
commonmark:
|
||||||
options: ["UNSAFE", "FOOTNOTES"]
|
options: ["UNSAFE", "FOOTNOTES"]
|
||||||
|
|
||||||
color_scheme: default
|
color_scheme: default
|
||||||
aux_links:
|
aux_links:
|
||||||
'<img src="https://img.shields.io/badge/GitHub--lightgrey?style=social&logo=github" alt="Schemars on GitHub" title="Schemars on GitHub">':
|
'<img src="https://img.shields.io/badge/GitHub--lightgrey?style=social&logo=github" alt="Schemars on GitHub" title="Schemars on GitHub">':
|
||||||
- "https://github.com/GREsau/schemars"
|
- "https://github.com/GREsau/schemars"
|
||||||
'<img src="https://img.shields.io/badge/API%20documentation--lightgrey?style=social" alt="Schemars API docs" title="Schemars API docs">':
|
'<img src="https://img.shields.io/badge/API%20documentation--lightgrey?style=social" alt="Schemars API docs" title="Schemars API docs">':
|
||||||
- "https://docs.rs/schemars"
|
- "https://docs.rs/schemars"
|
||||||
'<img src="https://img.shields.io/crates/v/schemars?style=social" alt="Schemars on crates.io" title="Schemars on crates.io">':
|
'<img src="https://img.shields.io/crates/v/schemars?style=social" alt="Schemars on crates.io" title="Schemars on crates.io">':
|
||||||
- "https://crates.io/crates/schemars"
|
- "https://crates.io/crates/schemars"
|
||||||
|
|
||||||
|
collections:
|
||||||
|
v0:
|
||||||
|
permalink: "/:collection/:path/"
|
||||||
|
output: true
|
||||||
|
|
||||||
|
just_the_docs:
|
||||||
|
collections:
|
||||||
|
v0:
|
||||||
|
name: v0.8
|
||||||
|
nav_fold: true
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
- scope:
|
||||||
|
path: ""
|
||||||
|
type: v0
|
||||||
|
values:
|
||||||
|
layout: v0
|
||||||
|
- scope:
|
||||||
|
path: ""
|
||||||
|
values:
|
||||||
|
layout: v1
|
||||||
|
|
||||||
|
callouts_level: quiet
|
||||||
|
callouts:
|
||||||
|
info:
|
||||||
|
color: blue
|
||||||
|
opacity: 0.1
|
||||||
# Exclude from processing.
|
# Exclude from processing.
|
||||||
# The following items will not be processed, by default.
|
# The following items will not be processed, by default.
|
||||||
# Any item listed under the `exclude:` key here will be automatically added to
|
# Any item listed under the `exclude:` key here will be automatically added to
|
||||||
|
|
14
docs/_includes/example_v0.md
Normal file
14
docs/_includes/example_v0.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% capture input %}examples/{{ include.name }}.rs{% endcapture %}
|
||||||
|
{% capture output %}examples/{{ include.name }}.schema.json{% endcapture %}
|
||||||
|
|
||||||
|
```rust
|
||||||
|
{% include {{ input }} %}
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click to see the output JSON schema...</summary>
|
||||||
|
|
||||||
|
```json
|
||||||
|
{% include {{ output }} -%}
|
||||||
|
```
|
||||||
|
</details>
|
|
@ -1,5 +1,4 @@
|
||||||
use schemars::schema::{Schema, SchemaObject};
|
use schemars::{schema_for, JsonSchema, Schema, SchemaGenerator};
|
||||||
use schemars::{gen::SchemaGenerator, schema_for, JsonSchema};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// `int_as_string` and `bool_as_string` use the schema for `String`.
|
// `int_as_string` and `bool_as_string` use the schema for `String`.
|
||||||
|
@ -21,9 +20,11 @@ pub struct MyStruct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_custom_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_custom_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema: SchemaObject = <String>::json_schema(gen).into();
|
let mut schema = String::json_schema(gen);
|
||||||
schema.format = Some("boolean".to_owned());
|
schema
|
||||||
schema.into()
|
.ensure_object()
|
||||||
|
.insert("format".into(), "boolean".into());
|
||||||
|
schema
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eight() -> i32 {
|
fn eight() -> i32 {
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"bool_as_string": {
|
"bool_as_string": {
|
||||||
"default": "false",
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "boolean"
|
"format": "boolean",
|
||||||
|
"default": "false"
|
||||||
},
|
},
|
||||||
"bool_normal": {
|
"bool_normal": {
|
||||||
"default": false,
|
"type": "boolean",
|
||||||
"type": "boolean"
|
"default": false
|
||||||
},
|
},
|
||||||
"int_as_string": {
|
"int_as_string": {
|
||||||
"default": "8",
|
"type": "string",
|
||||||
"type": "string"
|
"default": "8"
|
||||||
},
|
},
|
||||||
"int_normal": {
|
"int_normal": {
|
||||||
"default": 8,
|
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32",
|
||||||
|
"default": 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -23,32 +19,30 @@
|
||||||
"nullable": true
|
"nullable": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool"
|
||||||
|
],
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -57,10 +51,16 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "My Amazing Struct",
|
"title": "My Amazing Struct",
|
||||||
"description": "This struct shows off generating a schema with a custom title and description.",
|
"description": "This struct shows off generating a schema with\n a custom title and description.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"description": "This bool has a description, but no title.",
|
"description": "This bool has a description, but no title.",
|
||||||
|
@ -22,7 +18,7 @@
|
||||||
"description": "This enum might be set, or it might not.",
|
"description": "This enum might be set, or it might not.",
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
|
@ -30,35 +26,33 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"title": "My Amazing Enum",
|
"title": "My Amazing Enum",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"description": "A wrapper around a `String`",
|
"description": "A wrapper around a `String`",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "A struct-like enum variant which contains some floats",
|
"description": "A struct-like enum variant which contains\n some floats",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"description": "The floats themselves",
|
"description": "The floats themselves",
|
||||||
|
@ -68,10 +62,16 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "SmallPrime",
|
"title": "SmallPrime",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"examples": [
|
|
||||||
{
|
|
||||||
"my_bool": true,
|
|
||||||
"my_int": 123,
|
|
||||||
"my_nullable_enum": {
|
|
||||||
"StringNewType": "foo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
|
@ -19,5 +10,14 @@
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"my_nullable_enum": true
|
"my_nullable_enum": true
|
||||||
}
|
},
|
||||||
|
"examples": [
|
||||||
|
{
|
||||||
|
"my_bool": true,
|
||||||
|
"my_int": 123,
|
||||||
|
"my_nullable_enum": {
|
||||||
|
"StringNewType": "foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -17,7 +13,7 @@
|
||||||
"my_nullable_enum": {
|
"my_nullable_enum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
|
@ -25,32 +21,30 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -59,10 +53,16 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "Process",
|
"title": "Process",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"command_line",
|
|
||||||
"durations",
|
|
||||||
"wall_time"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"command_line": {
|
"command_line": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -14,20 +9,21 @@
|
||||||
"durations": {
|
"durations": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/Duration"
|
"$ref": "#/$defs/Duration"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wall_time": {
|
"wall_time": {
|
||||||
"$ref": "#/definitions/Duration"
|
"$ref": "#/$defs/Duration"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"command_line",
|
||||||
|
"wall_time",
|
||||||
|
"durations"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"Duration": {
|
"Duration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"nanos",
|
|
||||||
"secs"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"nanos": {
|
"nanos": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -37,7 +33,11 @@
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int64"
|
"format": "int64"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"secs",
|
||||||
|
"nanos"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use schemars::{schema_for, JsonSchema};
|
use schemars::{schema_for, JsonSchema, Schema};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, JsonSchema)]
|
#[derive(Deserialize, Serialize, JsonSchema)]
|
||||||
#[schemars(rename_all = "camelCase", deny_unknown_fields)]
|
#[schemars(rename_all = "camelCase", deny_unknown_fields, extend("x-customProperty" = "example"))]
|
||||||
pub struct MyStruct {
|
pub struct MyStruct {
|
||||||
#[serde(rename = "thisIsOverridden")]
|
#[serde(rename = "thisIsOverridden")]
|
||||||
#[schemars(rename = "myNumber", range(min = 1, max = 10))]
|
#[schemars(rename = "myNumber", range(min = 1, max = 10), transform = remove_format)]
|
||||||
pub my_int: i32,
|
pub my_int: i32,
|
||||||
pub my_bool: bool,
|
pub my_bool: bool,
|
||||||
#[schemars(default)]
|
#[schemars(default)]
|
||||||
|
@ -24,6 +24,12 @@ pub enum MyEnum {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_format(schema: &mut Schema) {
|
||||||
|
if let Some(obj) = schema.as_object_mut() {
|
||||||
|
obj.remove("format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let schema = schema_for!(MyStruct);
|
let schema = schema_for!(MyStruct);
|
||||||
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
|
|
@ -1,32 +1,26 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"myBool",
|
|
||||||
"myNumber",
|
|
||||||
"myVecStr"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"myBool": {
|
"myBool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"myNullableEnum": {
|
"myNullableEnum": {
|
||||||
"default": null,
|
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"default": null
|
||||||
},
|
},
|
||||||
"myNumber": {
|
"myNumber": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32",
|
"maximum": 10,
|
||||||
"maximum": 10.0,
|
"minimum": 1
|
||||||
"minimum": 1.0
|
|
||||||
},
|
},
|
||||||
"myVecStr": {
|
"myVecStr": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -37,7 +31,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"myNumber",
|
||||||
|
"myBool",
|
||||||
|
"myVecStr"
|
||||||
|
],
|
||||||
|
"x-customProperty": "example",
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
@ -46,9 +46,6 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -59,7 +56,10 @@
|
||||||
"maxItems": 100,
|
"maxItems": 100,
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"myBool",
|
|
||||||
"myNumber"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"myBool": {
|
"myBool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"myNullableEnum": {
|
"myNullableEnum": {
|
||||||
"default": null,
|
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"default": null
|
||||||
},
|
},
|
||||||
"myNumber": {
|
"myNumber": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -27,7 +23,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"myNumber",
|
||||||
|
"myBool"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
@ -35,9 +35,6 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -46,7 +43,10 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int",
|
|
||||||
"my_nullable_enum"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -14,35 +9,29 @@
|
||||||
"my_int": {
|
"my_int": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32",
|
"format": "int32",
|
||||||
"maximum": 10.0,
|
"maximum": 10,
|
||||||
"minimum": 1.0
|
"minimum": 1
|
||||||
},
|
},
|
||||||
"my_nullable_enum": {
|
"my_nullable_enum": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "phone"
|
"format": "phone"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -53,12 +42,23 @@
|
||||||
"maxItems": 100,
|
"maxItems": 100,
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool",
|
||||||
|
"my_nullable_enum"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
60
docs/_includes/examples_v0/custom_serialization.rs
Normal file
60
docs/_includes/examples_v0/custom_serialization.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
use schemars::schema::{Schema, SchemaObject};
|
||||||
|
use schemars::{gen::SchemaGenerator, schema_for, JsonSchema};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
// `int_as_string` and `bool_as_string` use the schema for `String`.
|
||||||
|
#[derive(Default, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
#[serde(default = "eight", with = "as_string")]
|
||||||
|
#[schemars(with = "String")]
|
||||||
|
pub int_as_string: i32,
|
||||||
|
|
||||||
|
#[serde(default = "eight")]
|
||||||
|
pub int_normal: i32,
|
||||||
|
|
||||||
|
#[serde(default, with = "as_string")]
|
||||||
|
#[schemars(schema_with = "make_custom_schema")]
|
||||||
|
pub bool_as_string: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub bool_normal: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_custom_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
|
let mut schema: SchemaObject = <String>::json_schema(gen).into();
|
||||||
|
schema.format = Some("boolean".to_owned());
|
||||||
|
schema.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eight() -> i32 {
|
||||||
|
8
|
||||||
|
}
|
||||||
|
|
||||||
|
// This module serializes values as strings
|
||||||
|
mod as_string {
|
||||||
|
use serde::{de::Error, Deserialize, Deserializer, Serializer};
|
||||||
|
|
||||||
|
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
T: std::fmt::Display,
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.collect_str(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||||
|
where
|
||||||
|
T: std::str::FromStr,
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let string = String::deserialize(deserializer)?;
|
||||||
|
string
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| D::Error::custom("Input was not valid"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(MyStruct);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
25
docs/_includes/examples_v0/custom_serialization.schema.json
Normal file
25
docs/_includes/examples_v0/custom_serialization.schema.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MyStruct",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"bool_as_string": {
|
||||||
|
"default": "false",
|
||||||
|
"type": "string",
|
||||||
|
"format": "boolean"
|
||||||
|
},
|
||||||
|
"bool_normal": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"int_as_string": {
|
||||||
|
"default": "8",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"int_normal": {
|
||||||
|
"default": 8,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
docs/_includes/examples_v0/custom_settings.rs
Normal file
24
docs/_includes/examples_v0/custom_settings.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use schemars::{gen::SchemaSettings, JsonSchema};
|
||||||
|
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
pub my_int: i32,
|
||||||
|
pub my_bool: bool,
|
||||||
|
pub my_nullable_enum: Option<MyEnum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
StringNewType(String),
|
||||||
|
StructVariant { floats: Vec<f32> },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let settings = SchemaSettings::draft07().with(|s| {
|
||||||
|
s.option_nullable = true;
|
||||||
|
s.option_add_null_type = false;
|
||||||
|
});
|
||||||
|
let gen = settings.into_generator();
|
||||||
|
let schema = gen.into_root_schema_for::<MyStruct>();
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
68
docs/_includes/examples_v0/custom_settings.schema.json
Normal file
68
docs/_includes/examples_v0/custom_settings.schema.json
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MyStruct",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"my_bool",
|
||||||
|
"my_int"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"my_bool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"my_int": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"my_nullable_enum": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MyEnum"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"MyEnum": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StringNewType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StructVariant": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"floats": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
docs/_includes/examples_v0/doc_comments.rs
Normal file
33
docs/_includes/examples_v0/doc_comments.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use schemars::{schema_for, JsonSchema};
|
||||||
|
|
||||||
|
/// # My Amazing Struct
|
||||||
|
/// This struct shows off generating a schema with
|
||||||
|
/// a custom title and description.
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
/// # My Amazing Integer
|
||||||
|
pub my_int: i32,
|
||||||
|
/// This bool has a description, but no title.
|
||||||
|
pub my_bool: bool,
|
||||||
|
/// # A Nullable Enum
|
||||||
|
/// This enum might be set, or it might not.
|
||||||
|
pub my_nullable_enum: Option<MyEnum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # My Amazing Enum
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
/// A wrapper around a `String`
|
||||||
|
StringNewType(String),
|
||||||
|
/// A struct-like enum variant which contains
|
||||||
|
/// some floats
|
||||||
|
StructVariant {
|
||||||
|
/// The floats themselves
|
||||||
|
floats: Vec<f32>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(MyStruct);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
79
docs/_includes/examples_v0/doc_comments.schema.json
Normal file
79
docs/_includes/examples_v0/doc_comments.schema.json
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "My Amazing Struct",
|
||||||
|
"description": "This struct shows off generating a schema with a custom title and description.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"my_bool",
|
||||||
|
"my_int"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"my_bool": {
|
||||||
|
"description": "This bool has a description, but no title.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"my_int": {
|
||||||
|
"title": "My Amazing Integer",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"my_nullable_enum": {
|
||||||
|
"title": "A Nullable Enum",
|
||||||
|
"description": "This enum might be set, or it might not.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MyEnum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"MyEnum": {
|
||||||
|
"title": "My Amazing Enum",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "A wrapper around a `String`",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StringNewType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "A struct-like enum variant which contains some floats",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StructVariant": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"floats": {
|
||||||
|
"description": "The floats themselves",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
docs/_includes/examples_v0/enum_repr.rs
Normal file
15
docs/_includes/examples_v0/enum_repr.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use schemars::{schema_for, JsonSchema_repr};
|
||||||
|
|
||||||
|
#[derive(JsonSchema_repr)]
|
||||||
|
#[repr(u8)]
|
||||||
|
enum SmallPrime {
|
||||||
|
Two = 2,
|
||||||
|
Three = 3,
|
||||||
|
Five = 5,
|
||||||
|
Seven = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(SmallPrime);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
11
docs/_includes/examples_v0/enum_repr.schema.json
Normal file
11
docs/_includes/examples_v0/enum_repr.schema.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "SmallPrime",
|
||||||
|
"type": "integer",
|
||||||
|
"enum": [
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
7
|
||||||
|
]
|
||||||
|
}
|
24
docs/_includes/examples_v0/from_value.rs
Normal file
24
docs/_includes/examples_v0/from_value.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use schemars::schema_for_value;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
pub my_int: i32,
|
||||||
|
pub my_bool: bool,
|
||||||
|
pub my_nullable_enum: Option<MyEnum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
StringNewType(String),
|
||||||
|
StructVariant { floats: Vec<f32> },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for_value!(MyStruct {
|
||||||
|
my_int: 123,
|
||||||
|
my_bool: true,
|
||||||
|
my_nullable_enum: Some(MyEnum::StringNewType("foo".to_string()))
|
||||||
|
});
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
23
docs/_includes/examples_v0/from_value.schema.json
Normal file
23
docs/_includes/examples_v0/from_value.schema.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MyStruct",
|
||||||
|
"examples": [
|
||||||
|
{
|
||||||
|
"my_bool": true,
|
||||||
|
"my_int": 123,
|
||||||
|
"my_nullable_enum": {
|
||||||
|
"StringNewType": "foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"my_bool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"my_int": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"my_nullable_enum": true
|
||||||
|
}
|
||||||
|
}
|
19
docs/_includes/examples_v0/main.rs
Normal file
19
docs/_includes/examples_v0/main.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use schemars::{schema_for, JsonSchema};
|
||||||
|
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
pub my_int: i32,
|
||||||
|
pub my_bool: bool,
|
||||||
|
pub my_nullable_enum: Option<MyEnum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
StringNewType(String),
|
||||||
|
StructVariant { floats: Vec<f32> },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(MyStruct);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
70
docs/_includes/examples_v0/main.schema.json
Normal file
70
docs/_includes/examples_v0/main.schema.json
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MyStruct",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"my_bool",
|
||||||
|
"my_int"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"my_bool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"my_int": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"my_nullable_enum": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MyEnum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"MyEnum": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StringNewType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StructVariant": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"floats": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
docs/_includes/examples_v0/remote_derive.rs
Normal file
42
docs/_includes/examples_v0/remote_derive.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Pretend that this is somebody else's crate, not a module.
|
||||||
|
mod other_crate {
|
||||||
|
// Neither Schemars nor the other crate provides a JsonSchema impl
|
||||||
|
// for this struct.
|
||||||
|
pub struct Duration {
|
||||||
|
pub secs: i64,
|
||||||
|
pub nanos: i32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
use other_crate::Duration;
|
||||||
|
use schemars::{schema_for, JsonSchema};
|
||||||
|
|
||||||
|
// This is just a copy of the remote data structure that Schemars can use to
|
||||||
|
// create a suitable JsonSchema impl.
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
#[serde(remote = "Duration")]
|
||||||
|
pub struct DurationDef {
|
||||||
|
pub secs: i64,
|
||||||
|
pub nanos: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now the remote type can be used almost like it had its own JsonSchema impl
|
||||||
|
// all along. The `with` attribute gives the path to the definition for the
|
||||||
|
// remote type. Note that the real type of the field is the remote type, not
|
||||||
|
// the definition type.
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub struct Process {
|
||||||
|
pub command_line: String,
|
||||||
|
#[serde(with = "DurationDef")]
|
||||||
|
pub wall_time: Duration,
|
||||||
|
// Generic types must be explicitly specified with turbofix `::<>` syntax.
|
||||||
|
#[serde(with = "Vec::<DurationDef>")]
|
||||||
|
pub durations: Vec<Duration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(Process);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
43
docs/_includes/examples_v0/remote_derive.schema.json
Normal file
43
docs/_includes/examples_v0/remote_derive.schema.json
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "Process",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"command_line",
|
||||||
|
"durations",
|
||||||
|
"wall_time"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"command_line": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"durations": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Duration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wall_time": {
|
||||||
|
"$ref": "#/definitions/Duration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"Duration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"nanos",
|
||||||
|
"secs"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"nanos": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"secs": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
docs/_includes/examples_v0/schemars_attrs.rs
Normal file
30
docs/_includes/examples_v0/schemars_attrs.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use schemars::{schema_for, JsonSchema};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, JsonSchema)]
|
||||||
|
#[schemars(rename_all = "camelCase", deny_unknown_fields)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
#[serde(rename = "thisIsOverridden")]
|
||||||
|
#[schemars(rename = "myNumber", range(min = 1, max = 10))]
|
||||||
|
pub my_int: i32,
|
||||||
|
pub my_bool: bool,
|
||||||
|
#[schemars(default)]
|
||||||
|
pub my_nullable_enum: Option<MyEnum>,
|
||||||
|
#[schemars(inner(regex(pattern = "^x$")))]
|
||||||
|
pub my_vec_str: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, JsonSchema)]
|
||||||
|
#[schemars(untagged)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
StringNewType(#[schemars(phone)] String),
|
||||||
|
StructVariant {
|
||||||
|
#[schemars(length(min = 1, max = 100))]
|
||||||
|
floats: Vec<f32>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(MyStruct);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
67
docs/_includes/examples_v0/schemars_attrs.schema.json
Normal file
67
docs/_includes/examples_v0/schemars_attrs.schema.json
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MyStruct",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"myBool",
|
||||||
|
"myNumber",
|
||||||
|
"myVecStr"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"myBool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"myNullableEnum": {
|
||||||
|
"default": null,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MyEnum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"myNumber": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"maximum": 10.0,
|
||||||
|
"minimum": 1.0
|
||||||
|
},
|
||||||
|
"myVecStr": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^x$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"definitions": {
|
||||||
|
"MyEnum": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "phone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"floats": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
},
|
||||||
|
"maxItems": 100,
|
||||||
|
"minItems": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
docs/_includes/examples_v0/serde_attrs.rs
Normal file
24
docs/_includes/examples_v0/serde_attrs.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use schemars::{schema_for, JsonSchema};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
#[serde(rename = "myNumber")]
|
||||||
|
pub my_int: i32,
|
||||||
|
pub my_bool: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub my_nullable_enum: Option<MyEnum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, JsonSchema)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
StringNewType(String),
|
||||||
|
StructVariant { floats: Vec<f32> },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(MyStruct);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
54
docs/_includes/examples_v0/serde_attrs.schema.json
Normal file
54
docs/_includes/examples_v0/serde_attrs.schema.json
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MyStruct",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"myBool",
|
||||||
|
"myNumber"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"myBool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"myNullableEnum": {
|
||||||
|
"default": null,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MyEnum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"myNumber": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"definitions": {
|
||||||
|
"MyEnum": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"floats": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
docs/_includes/examples_v0/validate.rs
Normal file
24
docs/_includes/examples_v0/validate.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use schemars::{schema_for, JsonSchema};
|
||||||
|
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub struct MyStruct {
|
||||||
|
#[validate(range(min = 1, max = 10))]
|
||||||
|
pub my_int: i32,
|
||||||
|
pub my_bool: bool,
|
||||||
|
#[validate(required)]
|
||||||
|
pub my_nullable_enum: Option<MyEnum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(JsonSchema)]
|
||||||
|
pub enum MyEnum {
|
||||||
|
StringNewType(#[validate(phone)] String),
|
||||||
|
StructVariant {
|
||||||
|
#[validate(length(min = 1, max = 100))]
|
||||||
|
floats: Vec<f32>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(MyStruct);
|
||||||
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
}
|
64
docs/_includes/examples_v0/validate.schema.json
Normal file
64
docs/_includes/examples_v0/validate.schema.json
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MyStruct",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"my_bool",
|
||||||
|
"my_int",
|
||||||
|
"my_nullable_enum"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"my_bool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"my_int": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"maximum": 10.0,
|
||||||
|
"minimum": 1.0
|
||||||
|
},
|
||||||
|
"my_nullable_enum": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StringNewType": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "phone"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"StructVariant": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"floats": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "float"
|
||||||
|
},
|
||||||
|
"maxItems": 100,
|
||||||
|
"minItems": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
docs/_layouts/v0.md
Normal file
10
docs/_layouts/v0.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
layout: default
|
||||||
|
---
|
||||||
|
|
||||||
|
<blockquote class="info">
|
||||||
|
<p>This page is for the current stable release of Schemars (v0.8.x).
|
||||||
|
<p>To view this page for the v1 version of Schemars, which is still under development, <a href="{{ page.url | remove_first: "/v0" | relative_url }}">click here</a>.
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
{{ content }}
|
10
docs/_layouts/v1.md
Normal file
10
docs/_layouts/v1.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
layout: default
|
||||||
|
---
|
||||||
|
|
||||||
|
<blockquote class="info">
|
||||||
|
<p>This page is for the current v1 alpha version of Schemars. This version is still under development, and further breaking changes may be introduced.
|
||||||
|
<p>To view this page for the current stable release of Schemars (v0.8.x), <a href="{{ page.url | prepend: "/v0" | relative_url }}">click here</a>.
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
{{ content }}
|
|
@ -4,7 +4,7 @@ $body-text-color: $grey-dk-200;
|
||||||
|
|
||||||
$nav-child-link-color: $link-color;
|
$nav-child-link-color: $link-color;
|
||||||
|
|
||||||
$content-width: 900px;
|
$content-width: 60rem;
|
||||||
|
|
||||||
$media-queries: (
|
$media-queries: (
|
||||||
xs: 320px,
|
xs: 320px,
|
||||||
|
|
|
@ -12,14 +12,14 @@ pre.highlight, figure.highlight {
|
||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
}
|
}
|
||||||
code {
|
code {
|
||||||
font-size: 14px;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always expand nav menu items
|
// Always expand nav menu items
|
||||||
.nav-list .nav-list-item > .nav-list {
|
.nav-list:not(.nav-category-list) .nav-list-item > .nav-list {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.nav-list-expander {
|
.nav-list:not(.nav-category-list) .nav-list-expander {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
docs/_v0/1-deriving.md
Normal file
36
docs/_v0/1-deriving.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
title: Deriving JsonSchema
|
||||||
|
nav_order: 2
|
||||||
|
has_children: true
|
||||||
|
has_toc: false
|
||||||
|
permalink: /v0/deriving/
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deriving JsonSchema
|
||||||
|
|
||||||
|
The most important trait in Schemars is `JsonSchema`, and the most important function of that trait is `json_schema(...)` which returns a JSON schema describing the type. Implementing this manually on many types would be slow and error-prone, so Schemars includes a derive macro which can implement that trait for you. Any derived implementation of `JsonSchema` should create a schema that describes the JSON representation of the type if it were to be serialized by serde_json.
|
||||||
|
|
||||||
|
Usually, all you need to do to use it is to add a `#[derive(JsonSchema)]` attribute to your type:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use schemars::{JsonSchema, schema_for};
|
||||||
|
|
||||||
|
#[derive(JsonSchema, Debug)]
|
||||||
|
struct Point {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = schema_for!(Point);
|
||||||
|
|
||||||
|
let serialized = serde_json::to_string(&schema).unwrap();
|
||||||
|
println!("{}", serialized);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- TODO:
|
||||||
|
show example output
|
||||||
|
requirements - when can/can't it be derived
|
||||||
|
generic params behaviour
|
||||||
|
-->
|
323
docs/_v0/1.1-attributes.md
Normal file
323
docs/_v0/1.1-attributes.md
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
---
|
||||||
|
title: Attributes
|
||||||
|
parent: Deriving JsonSchema
|
||||||
|
nav_order: 1
|
||||||
|
permalink: /v0/deriving/attributes/
|
||||||
|
---
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h3 code {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
# Attributes
|
||||||
|
|
||||||
|
You can add attributes to your types to customize Schemars's derived `JsonSchema` implementation.
|
||||||
|
|
||||||
|
[Serde](https://serde.rs/) allows setting `#[serde(...)]` attributes which change how types are serialized, and Schemars will generally respect these attributes to ensure that generated schemas will match how the type is serialized by serde_json. `#[serde(...)]` attributes can be overriden using `#[schemars(...)]` attributes, which behave identically (e.g. `#[schemars(rename_all = "camelCase")]`). You may find this useful if you want to change the generated schema without affecting Serde's behaviour, or if you're just not using Serde.
|
||||||
|
|
||||||
|
[Validator](https://github.com/Keats/validator) allows setting `#[validate(...)]` attributes to restrict valid values of particular fields, many of which will be used by Schemars to generate more accurate schemas. These can also be overridden by `#[schemars(...)]` attributes.
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary style="font-weight: bold">
|
||||||
|
TABLE OF CONTENTS
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
1. [Supported Serde Attributes](#supported-serde-attributes)
|
||||||
|
- [`rename`](#rename)
|
||||||
|
- [`rename_all`](#rename_all)
|
||||||
|
- [`tag` / `content` / `untagged`](#tag)
|
||||||
|
- [`default`](#default)
|
||||||
|
- [`skip`](#skip)
|
||||||
|
- [`skip_serializing`](#skip_serializing)
|
||||||
|
- [`skip_deserializing`](#skip_deserializing)
|
||||||
|
- [`flatten`](#flatten)
|
||||||
|
- [`with`](#with)
|
||||||
|
- [`bound`](#bound)
|
||||||
|
1. [Supported Validator Attributes](#supported-validator-attributes)
|
||||||
|
- [`email` / `phone` / `url`](#email-phone-url)
|
||||||
|
- [`length`](#length)
|
||||||
|
- [`range`](#range)
|
||||||
|
- [`regex`](#regex)
|
||||||
|
- [`contains`](#contains)
|
||||||
|
- [`required` / `required_nested`](#required)
|
||||||
|
1. [Other Attributes](#other-attributes)
|
||||||
|
- [`schema_with`](#schema_with)
|
||||||
|
- [`title` / `description`](#title-description)
|
||||||
|
- [`example`](#example)
|
||||||
|
- [`deprecated`](#deprecated)
|
||||||
|
- [`crate`](#crate)
|
||||||
|
- [Doc Comments (`doc`)](#doc)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Supported Serde Attributes
|
||||||
|
|
||||||
|
<div class="indented">
|
||||||
|
|
||||||
|
<h3 id="rename">
|
||||||
|
|
||||||
|
`#[serde(rename = "name")]` / `#[schemars(rename = "name")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a struct, enum, field or variant to use the given name in the generated schema instead of the Rust name. When used on a struct or enum, the given name will be used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
|
||||||
|
|
||||||
|
If set on a struct or enum with generic type parameters, then the given name may contain them enclosed in curly braces (e.g. `{T}`) and they will be replaced with the concrete type names when the schema is generated.
|
||||||
|
|
||||||
|
Serde docs: [container](https://serde.rs/container-attrs.html#rename) / [variant](https://serde.rs/variant-attrs.html#rename) / [field](https://serde.rs/field-attrs.html#rename)
|
||||||
|
|
||||||
|
<h3 id="rename_all">
|
||||||
|
|
||||||
|
`#[serde(rename_all = "...")]` / `#[schemars(rename_all = "...")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a struct, enum or variant to rename all fields according to the given case convention (see the Serde docs for details).
|
||||||
|
|
||||||
|
Serde docs: [container](https://serde.rs/container-attrs.html#rename_all) / [variant](https://serde.rs/variant-attrs.html#rename_all)
|
||||||
|
|
||||||
|
<h3 id="tag" style="line-height: 1.5">
|
||||||
|
|
||||||
|
`#[serde(tag = "type")]` / `#[schemars(tag = "type")]` <br />
|
||||||
|
`#[serde(tag = "t", content = "c")]` / `#[schemars(tag = "t", content = "c")]` <br />
|
||||||
|
`#[serde(untagged)]` / `#[schemars(untagged)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on an enum to generate the schema for the [internally tagged](https://serde.rs/enum-representations.html#internally-tagged), [adjacently tagged](https://serde.rs/enum-representations.html#adjacently-tagged), or [untagged](https://serde.rs/enum-representations.html#untagged) representation of this enum.
|
||||||
|
|
||||||
|
Serde docs: [`tag`](https://serde.rs/container-attrs.html#tag) / [`tag`+`content`](https://serde.rs/container-attrs.html#tag--content) / [`untagged`](https://serde.rs/container-attrs.html#untagged)
|
||||||
|
|
||||||
|
<h3 id="default">
|
||||||
|
|
||||||
|
`#[serde(default)]` / `#[schemars(default)]` / `#[serde(default = "path")]` / `#[schemars(default = "path")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a struct or field to give fields a default value, which excludes them from the schema's `required` properties. The default will also be set on the field's schema's `default` property, unless it is skipped by a [`skip_serializing_if`](https://serde.rs/field-attrs.html#skip_serializing_if) attribute on the field. Any [`serialize_with`](https://serde.rs/field-attrs.html#serialize_with) or [`with`](https://serde.rs/field-attrs.html#with) attribute set on the field will be used to serialize the default value.
|
||||||
|
|
||||||
|
Serde docs: [container](https://serde.rs/container-attrs.html#default) / [field](https://serde.rs/field-attrs.html#default)
|
||||||
|
|
||||||
|
<h3 id="skip">
|
||||||
|
|
||||||
|
`#[serde(skip)]` / `#[schemars(skip)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a variant or field to prevent it from appearing in any generated schema.
|
||||||
|
|
||||||
|
Serde docs: [variant](https://serde.rs/variant-attrs.html#skip) / [field](https://serde.rs/field-attrs.html#skip)
|
||||||
|
|
||||||
|
<h3 id="skip_serializing">
|
||||||
|
|
||||||
|
`#[serde(skip_serializing)]` / `#[schemars(skip_serializing)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a field of a (non-tuple) struct to set the `writeOnly` property on that field's schema. Serde also allows this attribute on variants or tuple struct fields, but this will have no effect on generated schemas.
|
||||||
|
|
||||||
|
Serde docs: [field](https://serde.rs/field-attrs.html#skip_deserializing)
|
||||||
|
|
||||||
|
<h3 id="skip_deserializing">
|
||||||
|
|
||||||
|
`#[serde(skip_deserializing)]` / `#[schemars(skip_deserializing)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a variant or field. When set on a field of a (non-tuple) struct, that field's schema will have the `readOnly` property set. When set on a variant or tuple struct field Schemars will treat this the same as a [`skip`](#skip) attribute.
|
||||||
|
|
||||||
|
Serde docs: [variant](https://serde.rs/variant-attrs.html#skip_deserializing) / [field](https://serde.rs/field-attrs.html#skip_deserializing)
|
||||||
|
|
||||||
|
<h3 id="flatten">
|
||||||
|
|
||||||
|
`#[serde(flatten)]` / `#[schemars(flatten)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a field to include that field's contents as though they belonged to the field's container.
|
||||||
|
|
||||||
|
Serde docs: [field](https://serde.rs/field-attrs.html#flatten)
|
||||||
|
|
||||||
|
<h3 id="with">
|
||||||
|
|
||||||
|
`#[serde(with = "Type")]` / `#[schemars(with = "Type")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a variant or field to generate its schema as the given type instead of its actual type. Serde allows the `with` attribute to refer to any module path, but Schemars requires this to be an actual type which implements `JsonSchema`.
|
||||||
|
|
||||||
|
If the given type has any required generic type parameters, then they must all be explicitly specified in this attribute. Serde frequently allows you to omit them as it can make use of type inference, but unfortunately this is not possible with Schemars. For example, `with = "Vec::<i32>"` will work, but `with = "Vec"` and `with = "Vec::<_>"` will not.
|
||||||
|
|
||||||
|
Serde docs: [variant](https://serde.rs/variant-attrs.html#with) / [field](https://serde.rs/field-attrs.html#with)
|
||||||
|
|
||||||
|
<h3 id="deny_unknown_fields">
|
||||||
|
|
||||||
|
`#[serde(deny_unknown_fields)]` / `#[schemars(deny_unknown_fields)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Setting this on a container will set the `additionalProperties` keyword on generated schemas to `false` to show that any extra properties are explicitly disallowed.
|
||||||
|
|
||||||
|
Serde docs: [container](https://serde.rs/container-attrs.html#deny_unknown_fields)
|
||||||
|
|
||||||
|
<h3 id="transparent">
|
||||||
|
|
||||||
|
`#[serde(transparent)]` / `#[schemars(transparent)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a newtype struct or a braced struct with one field to make the struct's generated schema exactly the same as that of the single field's.
|
||||||
|
|
||||||
|
Serde docs: [container](https://serde.rs/container-attrs.html#transparent)
|
||||||
|
|
||||||
|
<h3 id="bound">
|
||||||
|
|
||||||
|
`#[schemars(bound = "...")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Where-clause for the JsonSchema impl. This replaces any trait bounds inferred by schemars. Schemars does **not** use trait bounds from `#[serde(bound)]` attributes.
|
||||||
|
|
||||||
|
Serde docs: [container](https://serde.rs/container-attrs.html#bound)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Supported Validator Attributes
|
||||||
|
|
||||||
|
<div class="indented">
|
||||||
|
|
||||||
|
<h3 id="email-phone-url">
|
||||||
|
|
||||||
|
`#[validate(email)]` / `#[schemars(email)]`<br />
|
||||||
|
`#[validate(phone)]` / `#[schemars(phone)]`<br />
|
||||||
|
`#[validate(url)]` / `#[schemars(url)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Sets the schema's `format` to `email`/`phone`/`uri`, as appropriate. Only one of these attributes may be present on a single field.
|
||||||
|
|
||||||
|
Validator docs: [email](https://github.com/Keats/validator#email) / [phone](https://github.com/Keats/validator#phone) / [url](https://github.com/Keats/validator#url)
|
||||||
|
|
||||||
|
<h3 id="length">
|
||||||
|
|
||||||
|
`#[validate(length(min = 1, max = 10))]` / `#[schemars(length(min = 1, max = 10))]`<br />
|
||||||
|
`#[validate(length(equal = 10))]` / `#[schemars(length(equal = 10))]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Sets the `minLength`/`maxLength` properties for string schemas, or the `minItems`/`maxItems` properties for array schemas.
|
||||||
|
|
||||||
|
Validator docs: [length](https://github.com/Keats/validator#length)
|
||||||
|
|
||||||
|
<h3 id="range">
|
||||||
|
|
||||||
|
`#[validate(range(min = 1, max = 10))]` / `#[schemars(range(min = 1, max = 10))]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Sets the `minimum`/`maximum` properties for number schemas.
|
||||||
|
|
||||||
|
Validator docs: [range](https://github.com/Keats/validator#range)
|
||||||
|
|
||||||
|
<h3 id="regex">
|
||||||
|
|
||||||
|
`#[validate(regex = "path::to::regex")]` / `#[schemars(regex = "path::to::regex")]`<br />
|
||||||
|
`#[schemars(regex(pattern = r"^\d+$"))]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Sets the `pattern` property for string schemas. The `path::to::regex` will typically refer to a [`Regex`](https://docs.rs/regex/*/regex/struct.Regex.html) instance, but Schemars allows it to be any value with a `to_string()` method.
|
||||||
|
|
||||||
|
Providing an inline regex pattern using `regex(pattern = ...)` is a Schemars extension, and not currently supported by the Validator crate. When using this form, you may want to use a `r"raw string literal"` so that `\\` characters in the regex pattern are not interpreted as escape sequences in the string.
|
||||||
|
|
||||||
|
Validator docs: [regex](https://github.com/Keats/validator#regex)
|
||||||
|
|
||||||
|
<h3 id="contains">
|
||||||
|
|
||||||
|
`#[validate(contains = "string")]` / `#[schemars(contains = "string")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
For string schemas, sets the `pattern` property to the given value, with any regex special characters escaped. For object schemas (e.g. when the attribute is set on a HashMap field), includes the value in the `required` property, indicating that the map must contain it as a key.
|
||||||
|
|
||||||
|
Validator docs: [contains](https://github.com/Keats/validator#contains)
|
||||||
|
|
||||||
|
<h3 id="required">
|
||||||
|
|
||||||
|
`#[validate(required)]` / `#[schemars(required)]`<br />
|
||||||
|
`#[validate(required_nested)]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
When set on an `Option<T>` field, this will create a schemas as though the field were a `T`.
|
||||||
|
|
||||||
|
Validator docs: [required](https://github.com/Keats/validator#required) / [required_nested](https://github.com/Keats/validator#required_nested)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Other Attributes
|
||||||
|
|
||||||
|
<h3 id="schema_with">
|
||||||
|
|
||||||
|
`#[schemars(schema_with = "some::function")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a variant or field to generate this field's schema using the given function. This function must be callable as `fn(&mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema`.
|
||||||
|
|
||||||
|
<h3 id="title-description">
|
||||||
|
|
||||||
|
`#[schemars(title = "Some title", description = "Some description")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a container, variant or field to set the generated schema's `title` and/or `description`. If present, these will be used instead of values from any [`doc` comments/attributes](#doc).
|
||||||
|
|
||||||
|
<h3 id="example">
|
||||||
|
|
||||||
|
`#[schemars(example = "some::function")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set on a container, variant or field to include the result of the given function in the generated schema's `examples`. The function should take no parameters and can return any type that implements serde's `Serialize` trait - it does not need to return the same type as the attached struct/field. This attribute can be repeated to specify multiple examples.
|
||||||
|
|
||||||
|
<h3 id="deprecated">
|
||||||
|
|
||||||
|
`#[deprecated]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set the Rust built-in [`deprecated`](https://doc.rust-lang.org/edition-guide/rust-2018/the-compiler/an-attribute-for-deprecation.html) attribute on a struct, enum, field or variant to set the generated schema's `deprecated` keyword to `true`.
|
||||||
|
|
||||||
|
<h3 id="crate">
|
||||||
|
|
||||||
|
`#[schemars(crate = "other_crate::schemars")]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Set the path to the schemars crate instance the generated code should depend on. This is mostly useful for other crates that depend on schemars in their macros.
|
||||||
|
|
||||||
|
<h3 id="inner">
|
||||||
|
|
||||||
|
`#[schemars(inner(...))]`
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
Sets properties specified by [validator attributes](#supported-validator-attributes) on items of an array schema. For example:
|
||||||
|
|
||||||
|
```rs
|
||||||
|
struct Struct {
|
||||||
|
#[schemars(inner(url, regex(pattern = "^https://")))]
|
||||||
|
urls: Vec<String>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<h3 id="doc">
|
||||||
|
|
||||||
|
Doc Comments (`#[doc = "..."]`)
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
If a struct, variant or field has any [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html#doc-comments) (or [`doc` attributes](https://doc.rust-lang.org/rustdoc/the-doc-attribute.html)), then these will be used as the generated schema's `description`. If the first line is an ATX-style markdown heading (i.e. it begins with a # character), then it will be used as the schema's `title`, and the remaining lines will be the `description`.
|
78
docs/_v0/2-implementing.md
Normal file
78
docs/_v0/2-implementing.md
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
---
|
||||||
|
title: Implementing JsonSchema
|
||||||
|
nav_order: 3
|
||||||
|
permalink: /v0/implementing/
|
||||||
|
---
|
||||||
|
|
||||||
|
# Implementing JsonSchema
|
||||||
|
|
||||||
|
[Deriving `JsonSchema`]({{ site.baseurl }}{% link 1-deriving.md %}) is usually the easiest way to enable JSON schema generation for your types. But if you need more customisation, you can also implement `JsonSchema` manually. This trait has two associated functions which must be implemented, and one which can optionally be implemented:
|
||||||
|
|
||||||
|
## schema_name
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn schema_name() -> String;
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns the human-readable friendly name of the type's schema, which frequently is just the name of the type itself. The schema name is used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
|
||||||
|
|
||||||
|
NB in a future version of schemars, it's likely that this function will be changed to return a `Cow<'static, str>`.
|
||||||
|
|
||||||
|
## schema_id
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn schema_id() -> Cow<'static, str>;
|
||||||
|
```
|
||||||
|
|
||||||
|
This function returns a unique identifier of the type's schema - if two types return the same `schema_id`, then Schemars will consider them identical types. Because of this, if a type takes any generic type parameters, then its ID should depend on the type arguments. For example, the implementation of this function for `Vec<T> where T: JsonSchema` is:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
Cow::Owned(
|
||||||
|
format!("[{}]", T::schema_id()))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`&mut Vec<&T>`, `LinkedList<T>`, `Mutex<LinkedList<Arc<T>>>`, and similar collection types also use that implementation, since they produce identical JSON schemas so they can be considered the same type.
|
||||||
|
|
||||||
|
For a type with no generic type arguments, a reasonable implementation of this function would be to return the type name including module path (in case there is a type with the same name in another module/crate), e.g.:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl JsonSchema for NonGenericType {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
// Exclude the module path to make the name in generated schemas clearer.
|
||||||
|
"NonGenericType".to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schema_id() -> Cow<'static, str> {
|
||||||
|
// Include the module, in case a type with the same name is in another module/crate
|
||||||
|
Cow::Borrowed(concat!(module_path!(), "::NonGenericType"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## json_schema
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn json_schema(gen: &mut gen::SchemaGenerator) -> Schema;
|
||||||
|
```
|
||||||
|
|
||||||
|
This function creates the JSON schema itself. The `gen` argument can be used to check the schema generation settings, or to get schemas for other types. If you do need schemas for other types, you should call the `gen.subschema_for::<T>()` method instead of `<T>::json_schema(gen)`, as `subschema_for` can add `T`'s schema to the root schema's `definitions` so that it does not need to be duplicated when used more than once.
|
||||||
|
|
||||||
|
`json_schema` should not return a `$ref` schema.
|
||||||
|
|
||||||
|
## is_referenceable (optional)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn is_referenceable() -> bool;
|
||||||
|
```
|
||||||
|
|
||||||
|
If this function returns `true`, then Schemars can re-use the generate schema where possible by adding it to the root schema's `definitions` and having other schemas reference it using the `$ref` keyword. This can greatly simplify schemas that include a particular type multiple times, especially if that type's schema is fairly complex.
|
||||||
|
|
||||||
|
Generally, this should return `false` for types with simple schemas (such as primitives). For more complex types, it should return `true`. For recursive types, this **must** return `true` to prevent infinite cycles when generating schemas.
|
||||||
|
|
||||||
|
The default implementation of this function returns `true` to reduce the chance of someone inadvertently causing infinite cycles with recursive types.
|
35
docs/_v0/3-generating.md
Normal file
35
docs/_v0/3-generating.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
title: Generating Schemas
|
||||||
|
nav_order: 4
|
||||||
|
permalink: /v0/generating/
|
||||||
|
---
|
||||||
|
|
||||||
|
# Generating Schemas
|
||||||
|
|
||||||
|
The easiest way to generate a schema for a type that implements is to use the [`schema_for!` macro](https://docs.rs/schemars/latest/schemars/macro.schema_for.html), like so:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let my_schema = schema_for!(MyStruct);
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a schema that conforms to [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
||||||
|
|
||||||
|
If you want more control over how the schema is generated, you can use the [`gen` module](https://docs.rs/schemars/latest/schemars/gen/). There are two main types in this module:
|
||||||
|
|
||||||
|
- [`SchemaSettings`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaSettings.html), which defines what JSON Schema features should be used when generating schemas (for example, how `Option`s should be represented).
|
||||||
|
- [`SchemaGenerator`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaGenerator.html), which manages the generation of a schema document.
|
||||||
|
|
||||||
|
See the API documentation for more info on how to use those types for custom schema generation.
|
||||||
|
|
||||||
|
## Schema from Example Value
|
||||||
|
|
||||||
|
If you want a schema for a type that can't/doesn't implement `JsonSchema`, but does implement `serde::Serialize`, then you can generate a JSON schema from a value of that type using the [`schema_for_value!` macro](https://docs.rs/schemars/latest/schemars/macro.schema_for_value.html). However, this schema will generally be less precise than if the type implemented `JsonSchema` - particularly when it involves enums, since schemars will not make any assumptions about the structure of an enum based on a single variant.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let value = MyStruct { foo = 123 };
|
||||||
|
let my_schema = schema_for_value!(value);
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- TODO:
|
||||||
|
create and link to example
|
||||||
|
-->
|
39
docs/_v0/4-features.md
Normal file
39
docs/_v0/4-features.md
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
title: Feature Flags
|
||||||
|
nav_order: 5
|
||||||
|
permalink: /v0/features/
|
||||||
|
---
|
||||||
|
|
||||||
|
# Feature Flags and Optional Dependencies
|
||||||
|
|
||||||
|
- `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro
|
||||||
|
- `impl_json_schema` - implements `JsonSchema` for Schemars types themselves
|
||||||
|
- `preserve_order` - keep the order of struct fields in `Schema` and `SchemaObject`
|
||||||
|
- `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature)
|
||||||
|
|
||||||
|
Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets):
|
||||||
|
|
||||||
|
- `chrono` - [chrono](https://crates.io/crates/chrono) (^0.4)
|
||||||
|
- `indexmap1` - [indexmap](https://crates.io/crates/indexmap) (^1.2)
|
||||||
|
- `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0)
|
||||||
|
- `either` - [either](https://crates.io/crates/either) (^1.3)
|
||||||
|
- `uuid08` - [uuid](https://crates.io/crates/uuid) (^0.8)
|
||||||
|
- `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0)
|
||||||
|
- `smallvec` - [smallvec](https://crates.io/crates/smallvec) (^1.0)
|
||||||
|
- `arrayvec05` - [arrayvec](https://crates.io/crates/arrayvec) (^0.5)
|
||||||
|
- `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7)
|
||||||
|
- `url` - [url](https://crates.io/crates/url) (^2.0)
|
||||||
|
- `bytes` - [bytes](https://crates.io/crates/bytes) (^1.0)
|
||||||
|
- `enumset` - [enumset](https://crates.io/crates/enumset) (^1.0)
|
||||||
|
- `rust_decimal` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0)
|
||||||
|
- `bigdecimal03` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.3)
|
||||||
|
- `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4)
|
||||||
|
- `smol_str` - [smol_str](https://crates.io/crates/smol_str) (^0.1.17)
|
||||||
|
- `semver` - [semver](https://crates.io/crates/semver) (^1.0.9)
|
||||||
|
|
||||||
|
For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
schemars = { version = "0.8", features = ["chrono"] }
|
||||||
|
```
|
8
docs/_v0/5-examples.md
Normal file
8
docs/_v0/5-examples.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
title: Examples
|
||||||
|
nav_order: 6
|
||||||
|
has_children: true
|
||||||
|
permalink: /v0/examples/
|
||||||
|
---
|
||||||
|
|
||||||
|
# Examples
|
12
docs/_v0/examples/1-derive_jsonschema.md
Normal file
12
docs/_v0/examples/1-derive_jsonschema.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: Deriving JsonSchema
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 1
|
||||||
|
summary: Deriving JsonSchema on a struct and enum.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deriving JsonSchema
|
||||||
|
|
||||||
|
This is the simplest usage of Schemars. Both types are made to derive `JsonSchema`, and the `schema_for!` macro is used to generate the schema itself.
|
||||||
|
|
||||||
|
{% include example_v0.md name="main" %}
|
14
docs/_v0/examples/2-serde_attrs.md
Normal file
14
docs/_v0/examples/2-serde_attrs.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
title: Using Serde Attributes
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 2
|
||||||
|
summary: "Deriving JsonSchema on types that use #[serde] attributes to customise serialization behaviour."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using Serde Attributes
|
||||||
|
|
||||||
|
One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/json) would serialize/deserialize to/from JSON. To support this, Schemars will check for any `#[serde(...)]` attributes on types that derive `JsonSchema`, and adjust the generated schema accordingly.
|
||||||
|
|
||||||
|
The list of supported `#[serde]` attributes are [documented here]({{ site.baseurl }}{% link 1.1-attributes.md %}#supported-serde-attributes).
|
||||||
|
|
||||||
|
{% include example_v0.md name="serde_attrs" %}
|
12
docs/_v0/examples/3-schemars_attrs.md
Normal file
12
docs/_v0/examples/3-schemars_attrs.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: Using Schemars Attributes
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 3
|
||||||
|
summary: "Deriving JsonSchema on types that use #[schemars] attributes to customise serialization behaviour."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using Serde Attributes
|
||||||
|
|
||||||
|
`#[serde(...)]` attributes can be overriden (or replaced) with `#[schemars(...)]` attributes, which behave identically. You may find this useful if you want to change the generated schema without affecting Serde's behaviour, or if you're just not using Serde.
|
||||||
|
|
||||||
|
{% include example_v0.md name="schemars_attrs" %}
|
12
docs/_v0/examples/4-custom_settings.md
Normal file
12
docs/_v0/examples/4-custom_settings.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: Custom Schema Settings
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 4
|
||||||
|
summary: Generating a schema using custom settings which changes how Option<T> is handled.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Custom Schema Settings
|
||||||
|
|
||||||
|
The `gen` module allows you to customise how schemas are generated. For example, the default behaviour for `Option<T>` is to include `null` in the schema's `type`s, but we can instead add a `nullable` property to its schema:
|
||||||
|
|
||||||
|
{% include example_v0.md name="custom_settings" %}
|
16
docs/_v0/examples/5-remote_derive.md
Normal file
16
docs/_v0/examples/5-remote_derive.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
title: Derive for Remote Crate
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 5
|
||||||
|
summary: Deriving JsonSchema implementations for a type in somebody else's crate.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deriving JsonSchema for a Type in a Different Crate
|
||||||
|
|
||||||
|
Rust's [orphan rule](https://doc.rust-lang.org/book/traits.html#rules-for-implementing-traits) requires that either the trait or the type for which you are implementing the trait must be defined in the same crate as the impl, so it is not possible to implement `JsonSchema` for a type in a different crate directly.
|
||||||
|
|
||||||
|
To work around this, Schemars provides a way of deriving `JsonSchema` implementations for types in other people's crates. The only catch is that you have to provide a definition of the type for Schemars's derive to process.
|
||||||
|
|
||||||
|
This is the same way that Serde allows remote deriving, which is why this page reads so similarly to [Serde's documentation](https://serde.rs/remote-derive.html)!
|
||||||
|
|
||||||
|
{% include example_v0.md name="remote_derive" %}
|
12
docs/_v0/examples/6-doc_comments.md
Normal file
12
docs/_v0/examples/6-doc_comments.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: Doc Comments
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 6
|
||||||
|
summary: Giving schemas a custom title and/or description using doc comments.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Setting a Custom Title and/or Description Using Doc Comments
|
||||||
|
|
||||||
|
If a struct, variant or field has any [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html#doc-comments) (or [`doc` attributes](https://doc.rust-lang.org/rustdoc/the-doc-attribute.html)), then these will be used as the generated schema's `description`. If the first line is an ATX-style markdown heading (i.e. it begins with a # character), then it will be used as the schema's `title`, and the remaining lines will be the `description`.
|
||||||
|
|
||||||
|
{% include example_v0.md name="doc_comments" %}
|
19
docs/_v0/examples/7-custom_serialization.md
Normal file
19
docs/_v0/examples/7-custom_serialization.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
title: Custom Serialization
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 7
|
||||||
|
summary: >-
|
||||||
|
If a field has a #[serde(with = "path")] attribute where "path" is not a type that implements JsonSchema,
|
||||||
|
then in order to derive JsonSchema on the type, it must also have a #[schemars(with = "Type")] attribute,
|
||||||
|
where "Type" implements JsonSchema.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deriving JsonSchema with Fields Using Custom Serialization
|
||||||
|
|
||||||
|
Serde allows you to change how a field is (de)serialized by setting a [`#[serde(with = "path")]`](https://serde.rs/field-attrs.html#with) attribute, where `$path::serialize` and `$path::deserialize` must be functions with the correct signature. Schemars supports the same attribute, but `path` must be a type implementing `JsonSchema`.
|
||||||
|
|
||||||
|
In order to derive `JsonSchema` on a type which includes a `#[serde(with = "path")]` attribute where `path` is not a type implementing `JsonSchema`, you'll need to override it with a suitable `#[schemars(with = "Type")]` or `#[schemars(schema_with = "path")]` attribute.
|
||||||
|
|
||||||
|
{% include example_v0.md name="custom_serialization" %}
|
||||||
|
|
||||||
|
Note that the `default` values in the schema are serialized as strings where appropriate.
|
13
docs/_v0/examples/8-enum_repr.md
Normal file
13
docs/_v0/examples/8-enum_repr.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: Serialize Enum as Number (serde_repr)
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 8
|
||||||
|
summary: >-
|
||||||
|
Generating a schema for with a C-like enum compatible with serde_repr.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Serialize Enum as Number (serde_repr Compatibility)
|
||||||
|
|
||||||
|
If you use the `#[repr(...)]` attribute on an enum to give it a C-like representation, then you may also want to use the [serde_repr](https://github.com/dtolnay/serde-repr) crate to serialize the enum values as numbers. In this case, you should use the corresponding `JsonSchema_repr` derive to ensure the schema for your type reflects how serde formats your type.
|
||||||
|
|
||||||
|
{% include example_v0.md name="enum_repr" %}
|
15
docs/_v0/examples/9-from_value.md
Normal file
15
docs/_v0/examples/9-from_value.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
title: Generate Schema from Example Value
|
||||||
|
parent: Examples
|
||||||
|
nav_order: 9
|
||||||
|
summary: >-
|
||||||
|
Generating a schema for a serializable value.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Generate Schema from Example Value
|
||||||
|
|
||||||
|
If you want a schema for a type that can't/doesn't implement `JsonSchema`, but does implement [`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html), then you can generate a JSON schema from a value of that type. However, this schema will generally be less precise than if the type implemented `JsonSchema` - particularly when it involves enums, since schemars will not make any assumptions about the structure of an enum based on a single variant.
|
||||||
|
|
||||||
|
{% include example_v0.md name="from_value" %}
|
||||||
|
|
||||||
|
Note that the schema for the enum is not very useful in this case, since schemars doesn't know anything about the second variant.
|
20
docs/_v0/index.md
Normal file
20
docs/_v0/index.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
title: Overview
|
||||||
|
has_children: true
|
||||||
|
nav_order: 1
|
||||||
|
permalink: /v0/
|
||||||
|
---
|
||||||
|
|
||||||
|
# Schemars
|
||||||
|
|
||||||
|
Schemars is a library to generate JSON Schema documents from Rust data structures.
|
||||||
|
|
||||||
|
This is built on Rust's trait system - any type which implements the [`JsonSchema`](https://docs.rs/schemars/latest/schemars/trait.JsonSchema.html) trait can have a JSON Schema generated describing that type. Schemars implements this on many standard library types, and provides a derive macro to automatically implement it on custom types.
|
||||||
|
|
||||||
|
One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/json) would serialize/deserialize to/from JSON. To support this, Schemars will check for any `#[serde(...)]` attributes on types that derive `JsonSchema`, and adjust the generated schema accordingly.
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
If you don't really care about the specifics, the easiest way to generate a JSON schema for your types is to `#[derive(JsonSchema)]` and use the `schema_for!` macro. All fields of the type must also implement `JsonSchema` - Schemars implements this for many standard library types.
|
||||||
|
|
||||||
|
{% include example.md name="main" %}
|
10
docs/docker-compose.yml
Normal file
10
docs/docker-compose.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
services:
|
||||||
|
jekyll:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
volumes:
|
||||||
|
- ".:/docs"
|
||||||
|
working_dir: "/docs"
|
||||||
|
ports:
|
||||||
|
- 4000:4000
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Deriving JsonSchema
|
title: Deriving JsonSchema
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 1
|
nav_order: 1
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Using Serde Attributes
|
title: Using Serde Attributes
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 2
|
nav_order: 2
|
||||||
summary: 'Deriving JsonSchema on types that use #[serde] attributes to customise serialization behaviour.'
|
summary: "Deriving JsonSchema on types that use #[serde] attributes to customise serialization behaviour."
|
||||||
---
|
---
|
||||||
|
|
||||||
# Using Serde Attributes
|
# Using Serde Attributes
|
||||||
|
|
||||||
One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema *should* match how [serde_json](https://github.com/serde-rs/json) would serialize/deserialize to/from JSON. To support this, Schemars will check for any `#[serde(...)]` attributes on types that derive `JsonSchema`, and adjust the generated schema accordingly.
|
One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/json) would serialize/deserialize to/from JSON. To support this, Schemars will check for any `#[serde(...)]` attributes on types that derive `JsonSchema`, and adjust the generated schema accordingly.
|
||||||
|
|
||||||
The list of supported `#[serde]` attributes are [documented here]({{ site.baseurl }}{% link 1.1-attributes.md %}#supported-serde-attributes).
|
The list of supported `#[serde]` attributes are [documented here]({{ site.baseurl }}{% link 1.1-attributes.md %}#supported-serde-attributes).
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Using Schemars Attributes
|
title: Using Schemars Attributes
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 3
|
nav_order: 3
|
||||||
summary: 'Deriving JsonSchema on types that use #[schemars] attributes to customise serialization behaviour.'
|
summary: "Deriving JsonSchema on types that use #[schemars] attributes to customise serialization behaviour."
|
||||||
---
|
---
|
||||||
|
|
||||||
# Using Serde Attributes
|
# Using Serde Attributes
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Custom Schema Settings
|
title: Custom Schema Settings
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 4
|
nav_order: 4
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Derive for Remote Crate
|
title: Derive for Remote Crate
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 5
|
nav_order: 5
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Doc Comments
|
title: Doc Comments
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 6
|
nav_order: 6
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Custom Serialization
|
title: Custom Serialization
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 7
|
nav_order: 7
|
||||||
|
@ -13,7 +12,7 @@ summary: >-
|
||||||
|
|
||||||
Serde allows you to change how a field is (de)serialized by setting a [`#[serde(with = "path")]`](https://serde.rs/field-attrs.html#with) attribute, where `$path::serialize` and `$path::deserialize` must be functions with the correct signature. Schemars supports the same attribute, but `path` must be a type implementing `JsonSchema`.
|
Serde allows you to change how a field is (de)serialized by setting a [`#[serde(with = "path")]`](https://serde.rs/field-attrs.html#with) attribute, where `$path::serialize` and `$path::deserialize` must be functions with the correct signature. Schemars supports the same attribute, but `path` must be a type implementing `JsonSchema`.
|
||||||
|
|
||||||
In order to derive `JsonSchema` on a type which includes a `#[serde(with = "path")]` attribute where `path` is not a type implementing `JsonSchema`, you'll need to override it with a suitable `#[schemars(with = "Type")]` or `#[schemars(schema_with = "path")]` attribute.
|
In order to derive `JsonSchema` on a type which includes a `#[serde(with = "path")]` attribute where `path` is not a type implementing `JsonSchema`, you'll need to override it with a suitable `#[schemars(with = "Type")]` or `#[schemars(schema_with = "path")]` attribute.
|
||||||
|
|
||||||
{% include example.md name="custom_serialization" %}
|
{% include example.md name="custom_serialization" %}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Serialize Enum as Number (serde_repr)
|
title: Serialize Enum as Number (serde_repr)
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 8
|
nav_order: 8
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Generate Schema from Example Value
|
title: Generate Schema from Example Value
|
||||||
parent: Examples
|
parent: Examples
|
||||||
nav_order: 9
|
nav_order: 9
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
---
|
---
|
||||||
layout: default
|
|
||||||
title: Overview
|
title: Overview
|
||||||
nav_order: 1
|
nav_order: 1
|
||||||
---
|
---
|
||||||
|
@ -10,7 +9,7 @@ Schemars is a library to generate JSON Schema documents from Rust data structure
|
||||||
|
|
||||||
This is built on Rust's trait system - any type which implements the [`JsonSchema`](https://docs.rs/schemars/latest/schemars/trait.JsonSchema.html) trait can have a JSON Schema generated describing that type. Schemars implements this on many standard library types, and provides a derive macro to automatically implement it on custom types.
|
This is built on Rust's trait system - any type which implements the [`JsonSchema`](https://docs.rs/schemars/latest/schemars/trait.JsonSchema.html) trait can have a JSON Schema generated describing that type. Schemars implements this on many standard library types, and provides a derive macro to automatically implement it on custom types.
|
||||||
|
|
||||||
One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema *should* match how [serde_json](https://github.com/serde-rs/json) would serialize/deserialize to/from JSON. To support this, Schemars will check for any `#[serde(...)]` attributes on types that derive `JsonSchema`, and adjust the generated schema accordingly.
|
One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/json) would serialize/deserialize to/from JSON. To support this, Schemars will check for any `#[serde(...)]` attributes on types that derive `JsonSchema`, and adjust the generated schema accordingly.
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ name = "schemars"
|
||||||
description = "Generate JSON Schemas from Rust code"
|
description = "Generate JSON Schemas from Rust code"
|
||||||
homepage = "https://graham.cool/schemars/"
|
homepage = "https://graham.cool/schemars/"
|
||||||
repository = "https://github.com/GREsau/schemars"
|
repository = "https://github.com/GREsau/schemars"
|
||||||
version = "0.8.21"
|
version = "1.0.0-alpha.3"
|
||||||
authors = ["Graham Esau <gesau@hotmail.co.uk>"]
|
authors = ["Graham Esau <gesau@hotmail.co.uk>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -14,118 +14,93 @@ build = "build.rs"
|
||||||
rust-version = "1.60"
|
rust-version = "1.60"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
schemars_derive = { version = "=0.8.21", optional = true, path = "../schemars_derive" }
|
schemars_derive = { version = "=1.0.0-alpha.3", optional = true, path = "../schemars_derive" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = "1.0"
|
||||||
serde_json = "1.0.25"
|
serde_json = "1.0.25"
|
||||||
dyn-clone = "1.0"
|
dyn-clone = "1.0"
|
||||||
|
ref-cast = "1.0.22"
|
||||||
|
|
||||||
chrono = { version = "0.4", default-features = false, optional = true }
|
# optional dependencies
|
||||||
indexmap = { version = "1.2", features = ["serde-1"], optional = true }
|
|
||||||
indexmap2 = { version = "2.0", features = ["serde"], optional = true, package = "indexmap" }
|
|
||||||
either = { version = "1.3", default-features = false, optional = true }
|
|
||||||
uuid08 = { version = "0.8", default-features = false, optional = true, package = "uuid" }
|
|
||||||
uuid1 = { version = "1.0", default-features = false, optional = true, package = "uuid" }
|
|
||||||
smallvec = { version = "1.0", optional = true }
|
|
||||||
arrayvec05 = { version = "0.5", default-features = false, optional = true, package = "arrayvec" }
|
|
||||||
arrayvec07 = { version = "0.7", default-features = false, optional = true, package = "arrayvec" }
|
arrayvec07 = { version = "0.7", default-features = false, optional = true, package = "arrayvec" }
|
||||||
url = { version = "2.0", default-features = false, optional = true }
|
|
||||||
bytes = { version = "1.0", optional = true }
|
|
||||||
rust_decimal = { version = "1", default-features = false, optional = true }
|
|
||||||
bigdecimal03 = { version = "0.3", default-features = false, optional = true, package = "bigdecimal" }
|
|
||||||
bigdecimal04 = { version = "0.4", default-features = false, optional = true, package = "bigdecimal" }
|
bigdecimal04 = { version = "0.4", default-features = false, optional = true, package = "bigdecimal" }
|
||||||
enumset = { version = "1.0", optional = true }
|
bytes1 = { version = "1.0", default-features = false, optional = true, package = "bytes" }
|
||||||
smol_str = { version = "0.1.17", optional = true }
|
chrono04 = { version = "0.4", default-features = false, optional = true, package = "chrono" }
|
||||||
semver = { version = "1.0.9", features = ["serde"], optional = true }
|
either1 = { version = "1.3", default-features = false, optional = true, package = "either" }
|
||||||
|
enumset1 = { version = "1.0", default-features = false, optional = true, package = "enumset" }
|
||||||
|
indexmap2 = { version = "2.0", default-features = false, optional = true, package = "indexmap" }
|
||||||
|
rust_decimal1 = { version = "1", default-features = false, optional = true, package = "rust_decimal"}
|
||||||
|
semver1 = { version = "1.0.9", default-features = false, optional = true, package = "semver" }
|
||||||
|
smallvec1 = { version = "1.0", default-features = false, optional = true, package = "smallvec" }
|
||||||
|
smol_str02 = { version = "0.2.1", default-features = false, optional = true, package = "smol_str" }
|
||||||
|
url2 = { version = "2.0", default-features = false, optional = true, package = "url" }
|
||||||
|
uuid1 = { version = "1.0", default-features = false, optional = true, package = "uuid" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.2.1"
|
pretty_assertions = "1.2.1"
|
||||||
trybuild = "1.0"
|
trybuild = "1.0"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["derive"]
|
default = ["derive"]
|
||||||
|
|
||||||
derive = ["schemars_derive"]
|
derive = ["schemars_derive"]
|
||||||
|
preserve_order = ["serde_json/preserve_order"]
|
||||||
# Use a different representation for the map type of Schemars.
|
|
||||||
# This allows data to be read into a Value and written back to a JSON string
|
|
||||||
# while preserving the order of map keys in the input.
|
|
||||||
preserve_order = ["indexmap"]
|
|
||||||
|
|
||||||
impl_json_schema = ["derive"]
|
|
||||||
# derive_json_schema will be removed in a later version
|
|
||||||
derive_json_schema = ["impl_json_schema"]
|
|
||||||
|
|
||||||
# `uuid` feature contains `uuid08` only for back-compat - will be changed to include uuid 1.0 instead in a later version
|
|
||||||
uuid = ["uuid08"]
|
|
||||||
# `arrayvec` feature without version suffix is included only for back-compat - will be removed in a later version
|
|
||||||
arrayvec = ["arrayvec05"]
|
|
||||||
indexmap1 = ["indexmap"]
|
|
||||||
|
|
||||||
raw_value = ["serde_json/raw_value"]
|
raw_value = ["serde_json/raw_value"]
|
||||||
# `bigdecimal` feature without version suffix is included only for back-compat - will be removed in a later version
|
|
||||||
bigdecimal = ["bigdecimal03"]
|
|
||||||
|
|
||||||
ui_test = []
|
ui_test = []
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "chrono"
|
|
||||||
required-features = ["chrono"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "indexmap"
|
|
||||||
required-features = ["indexmap"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "indexmap2"
|
|
||||||
required-features = ["indexmap2"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "either"
|
|
||||||
required-features = ["either"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "uuid"
|
|
||||||
required-features = ["uuid08", "uuid1"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "smallvec"
|
|
||||||
required-features = ["smallvec"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "bytes"
|
|
||||||
required-features = ["bytes"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "arrayvec"
|
|
||||||
required-features = ["arrayvec05", "arrayvec07"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "schema_for_schema"
|
|
||||||
required-features = ["impl_json_schema"]
|
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "ui"
|
name = "ui"
|
||||||
required-features = ["ui_test"]
|
required-features = ["ui_test"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "chrono"
|
||||||
|
required-features = ["chrono04"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "indexmap"
|
||||||
|
required-features = ["indexmap2"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "either"
|
||||||
|
required-features = ["either1"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "uuid"
|
||||||
|
required-features = ["uuid1"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "smallvec"
|
||||||
|
required-features = ["smallvec1"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "bytes"
|
||||||
|
required-features = ["bytes1"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "arrayvec"
|
||||||
|
required-features = ["arrayvec07"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "url"
|
name = "url"
|
||||||
required-features = ["url"]
|
required-features = ["url2"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "enumset"
|
name = "enumset"
|
||||||
required-features = ["enumset"]
|
required-features = ["enumset1"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "smol_str"
|
name = "smol_str"
|
||||||
required-features = ["smol_str"]
|
required-features = ["smol_str02"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
required-features = ["semver"]
|
required-features = ["semver1"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "decimal"
|
name = "decimal"
|
||||||
required-features = ["rust_decimal", "bigdecimal03", "bigdecimal04"]
|
required-features = ["rust_decimal1", "bigdecimal04"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use schemars::schema::{Schema, SchemaObject};
|
use schemars::{schema_for, JsonSchema, Schema, SchemaGenerator};
|
||||||
use schemars::{gen::SchemaGenerator, schema_for, JsonSchema};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// `int_as_string` and `bool_as_string` use the schema for `String`.
|
// `int_as_string` and `bool_as_string` use the schema for `String`.
|
||||||
|
@ -21,9 +20,11 @@ pub struct MyStruct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_custom_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_custom_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema: SchemaObject = <String>::json_schema(gen).into();
|
let mut schema = String::json_schema(gen);
|
||||||
schema.format = Some("boolean".to_owned());
|
schema
|
||||||
schema.into()
|
.ensure_object()
|
||||||
|
.insert("format".into(), "boolean".into());
|
||||||
|
schema
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eight() -> i32 {
|
fn eight() -> i32 {
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"bool_as_string": {
|
"bool_as_string": {
|
||||||
"default": "false",
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "boolean"
|
"format": "boolean",
|
||||||
|
"default": "false"
|
||||||
},
|
},
|
||||||
"bool_normal": {
|
"bool_normal": {
|
||||||
"default": false,
|
"type": "boolean",
|
||||||
"type": "boolean"
|
"default": false
|
||||||
},
|
},
|
||||||
"int_as_string": {
|
"int_as_string": {
|
||||||
"default": "8",
|
"type": "string",
|
||||||
"type": "string"
|
"default": "8"
|
||||||
},
|
},
|
||||||
"int_normal": {
|
"int_normal": {
|
||||||
"default": 8,
|
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"format": "int32",
|
||||||
|
"default": 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -23,32 +19,30 @@
|
||||||
"nullable": true
|
"nullable": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool"
|
||||||
|
],
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -57,10 +51,16 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "My Amazing Struct",
|
"title": "My Amazing Struct",
|
||||||
"description": "This struct shows off generating a schema with a custom title and description.",
|
"description": "This struct shows off generating a schema with\n a custom title and description.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"description": "This bool has a description, but no title.",
|
"description": "This bool has a description, but no title.",
|
||||||
|
@ -22,7 +18,7 @@
|
||||||
"description": "This enum might be set, or it might not.",
|
"description": "This enum might be set, or it might not.",
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
|
@ -30,35 +26,33 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"title": "My Amazing Enum",
|
"title": "My Amazing Enum",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"description": "A wrapper around a `String`",
|
"description": "A wrapper around a `String`",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "A struct-like enum variant which contains some floats",
|
"description": "A struct-like enum variant which contains\n some floats",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"description": "The floats themselves",
|
"description": "The floats themselves",
|
||||||
|
@ -68,10 +62,16 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "SmallPrime",
|
"title": "SmallPrime",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"examples": [
|
|
||||||
{
|
|
||||||
"my_bool": true,
|
|
||||||
"my_int": 123,
|
|
||||||
"my_nullable_enum": {
|
|
||||||
"StringNewType": "foo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
|
@ -19,5 +10,14 @@
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"my_nullable_enum": true
|
"my_nullable_enum": true
|
||||||
}
|
},
|
||||||
|
"examples": [
|
||||||
|
{
|
||||||
|
"my_bool": true,
|
||||||
|
"my_int": 123,
|
||||||
|
"my_nullable_enum": {
|
||||||
|
"StringNewType": "foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -17,7 +13,7 @@
|
||||||
"my_nullable_enum": {
|
"my_nullable_enum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
|
@ -25,32 +21,30 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -59,10 +53,16 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "Process",
|
"title": "Process",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"command_line",
|
|
||||||
"durations",
|
|
||||||
"wall_time"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"command_line": {
|
"command_line": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -14,20 +9,21 @@
|
||||||
"durations": {
|
"durations": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/Duration"
|
"$ref": "#/$defs/Duration"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wall_time": {
|
"wall_time": {
|
||||||
"$ref": "#/definitions/Duration"
|
"$ref": "#/$defs/Duration"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"command_line",
|
||||||
|
"wall_time",
|
||||||
|
"durations"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"Duration": {
|
"Duration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"nanos",
|
|
||||||
"secs"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"nanos": {
|
"nanos": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -37,7 +33,11 @@
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int64"
|
"format": "int64"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"secs",
|
||||||
|
"nanos"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use schemars::{schema_for, JsonSchema};
|
use schemars::{schema_for, JsonSchema, Schema};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, JsonSchema)]
|
#[derive(Deserialize, Serialize, JsonSchema)]
|
||||||
#[schemars(rename_all = "camelCase", deny_unknown_fields)]
|
#[schemars(rename_all = "camelCase", deny_unknown_fields, extend("x-customProperty" = "example"))]
|
||||||
pub struct MyStruct {
|
pub struct MyStruct {
|
||||||
#[serde(rename = "thisIsOverridden")]
|
#[serde(rename = "thisIsOverridden")]
|
||||||
#[schemars(rename = "myNumber", range(min = 1, max = 10))]
|
#[schemars(rename = "myNumber", range(min = 1, max = 10), transform = remove_format)]
|
||||||
pub my_int: i32,
|
pub my_int: i32,
|
||||||
pub my_bool: bool,
|
pub my_bool: bool,
|
||||||
#[schemars(default)]
|
#[schemars(default)]
|
||||||
|
@ -24,6 +24,12 @@ pub enum MyEnum {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_format(schema: &mut Schema) {
|
||||||
|
if let Some(obj) = schema.as_object_mut() {
|
||||||
|
obj.remove("format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let schema = schema_for!(MyStruct);
|
let schema = schema_for!(MyStruct);
|
||||||
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
|
|
@ -1,32 +1,26 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"myBool",
|
|
||||||
"myNumber",
|
|
||||||
"myVecStr"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"myBool": {
|
"myBool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"myNullableEnum": {
|
"myNullableEnum": {
|
||||||
"default": null,
|
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"default": null
|
||||||
},
|
},
|
||||||
"myNumber": {
|
"myNumber": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32",
|
"maximum": 10,
|
||||||
"maximum": 10.0,
|
"minimum": 1
|
||||||
"minimum": 1.0
|
|
||||||
},
|
},
|
||||||
"myVecStr": {
|
"myVecStr": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -37,7 +31,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"myNumber",
|
||||||
|
"myBool",
|
||||||
|
"myVecStr"
|
||||||
|
],
|
||||||
|
"x-customProperty": "example",
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
@ -46,9 +46,6 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -59,7 +56,10 @@
|
||||||
"maxItems": 100,
|
"maxItems": 100,
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"myBool",
|
|
||||||
"myNumber"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"myBool": {
|
"myBool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"myNullableEnum": {
|
"myNullableEnum": {
|
||||||
"default": null,
|
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/definitions/MyEnum"
|
"$ref": "#/$defs/MyEnum"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"default": null
|
||||||
},
|
},
|
||||||
"myNumber": {
|
"myNumber": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -27,7 +23,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"definitions": {
|
"required": [
|
||||||
|
"myNumber",
|
||||||
|
"myBool"
|
||||||
|
],
|
||||||
|
"$defs": {
|
||||||
"MyEnum": {
|
"MyEnum": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
@ -35,9 +35,6 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -46,7 +43,10 @@
|
||||||
"format": "float"
|
"format": "float"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "MyStruct",
|
"title": "MyStruct",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"my_bool",
|
|
||||||
"my_int",
|
|
||||||
"my_nullable_enum"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"my_bool": {
|
"my_bool": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -14,35 +9,29 @@
|
||||||
"my_int": {
|
"my_int": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32",
|
"format": "int32",
|
||||||
"maximum": 10.0,
|
"maximum": 10,
|
||||||
"minimum": 1.0
|
"minimum": 1
|
||||||
},
|
},
|
||||||
"my_nullable_enum": {
|
"my_nullable_enum": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StringNewType"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StringNewType": {
|
"StringNewType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "phone"
|
"format": "phone"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StringNewType"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"StructVariant"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"StructVariant": {
|
"StructVariant": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
|
||||||
"floats"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"floats": {
|
"floats": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -53,12 +42,23 @@
|
||||||
"maxItems": 100,
|
"maxItems": 100,
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"floats"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"StructVariant"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"my_int",
|
||||||
|
"my_bool",
|
||||||
|
"my_nullable_enum"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::{JsonSchema, Schema, SchemaGenerator};
|
||||||
use crate::schema::{InstanceType, ObjectValidation, Schema, SchemaObject};
|
|
||||||
use crate::{JsonSchema, Map, Set};
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::Value;
|
use serde_json::{json, map::Entry, Map, Value};
|
||||||
|
|
||||||
// Helper for generating schemas for flattened `Option` fields.
|
// Helper for generating schemas for flattened `Option` fields.
|
||||||
pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(
|
pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(
|
||||||
|
@ -12,12 +10,8 @@ pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(
|
||||||
let mut schema = T::_schemars_private_non_optional_json_schema(gen);
|
let mut schema = T::_schemars_private_non_optional_json_schema(gen);
|
||||||
|
|
||||||
if T::_schemars_private_is_option() && !required {
|
if T::_schemars_private_is_option() && !required {
|
||||||
if let Schema::Object(SchemaObject {
|
if let Some(object) = schema.as_object_mut() {
|
||||||
object: Some(ref mut object_validation),
|
object.remove("required");
|
||||||
..
|
|
||||||
}) = schema
|
|
||||||
{
|
|
||||||
object_validation.required.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,117 +49,183 @@ impl<T: Serialize> MaybeSerializeWrapper<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a schema for a unit enum
|
/// Create a schema for a unit enum variant
|
||||||
pub fn new_unit_enum(variant: &str) -> Schema {
|
pub fn new_unit_enum_variant(variant: &str) -> Schema {
|
||||||
Schema::Object(SchemaObject {
|
json_schema!({
|
||||||
instance_type: Some(InstanceType::String.into()),
|
"type": "string",
|
||||||
enum_values: Some(vec![variant.into()]),
|
"const": variant,
|
||||||
..SchemaObject::default()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a schema for an externally tagged enum
|
/// Create a schema for an externally tagged enum variant
|
||||||
pub fn new_externally_tagged_enum(variant: &str, sub_schema: Schema) -> Schema {
|
pub fn new_externally_tagged_enum_variant(variant: &str, sub_schema: Schema) -> Schema {
|
||||||
Schema::Object(SchemaObject {
|
json_schema!({
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
"type": "object",
|
||||||
object: Some(Box::new(ObjectValidation {
|
"properties": {
|
||||||
properties: {
|
variant: sub_schema
|
||||||
let mut props = Map::new();
|
},
|
||||||
props.insert(variant.to_owned(), sub_schema);
|
"required": [variant],
|
||||||
props
|
"additionalProperties": false,
|
||||||
},
|
|
||||||
required: {
|
|
||||||
let mut required = Set::new();
|
|
||||||
required.insert(variant.to_owned());
|
|
||||||
required
|
|
||||||
},
|
|
||||||
// Externally tagged variants must prohibit additional
|
|
||||||
// properties irrespective of the disposition of
|
|
||||||
// `deny_unknown_fields`. If additional properties were allowed
|
|
||||||
// one could easily construct an object that validated against
|
|
||||||
// multiple variants since here it's the properties rather than
|
|
||||||
// the values of a property that distingish between variants.
|
|
||||||
additional_properties: Some(Box::new(false.into())),
|
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
..SchemaObject::default()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a schema for an internally tagged enum
|
/// Update a schema for an internally tagged enum variant
|
||||||
pub fn new_internally_tagged_enum(
|
pub fn apply_internal_enum_variant_tag(
|
||||||
|
schema: &mut Schema,
|
||||||
tag_name: &str,
|
tag_name: &str,
|
||||||
variant: &str,
|
variant: &str,
|
||||||
deny_unknown_fields: bool,
|
deny_unknown_fields: bool,
|
||||||
) -> Schema {
|
) {
|
||||||
let tag_schema = Schema::Object(SchemaObject {
|
let obj = schema.ensure_object();
|
||||||
instance_type: Some(InstanceType::String.into()),
|
let is_unit = obj.get("type").and_then(|t| t.as_str()) == Some("null");
|
||||||
enum_values: Some(vec![variant.into()]),
|
|
||||||
..Default::default()
|
obj.insert("type".to_owned(), "object".into());
|
||||||
});
|
|
||||||
Schema::Object(SchemaObject {
|
if let Some(properties) = obj
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
.entry("properties")
|
||||||
object: Some(Box::new(ObjectValidation {
|
.or_insert(Value::Object(Map::new()))
|
||||||
properties: {
|
.as_object_mut()
|
||||||
let mut props = Map::new();
|
{
|
||||||
props.insert(tag_name.to_owned(), tag_schema);
|
properties.insert(
|
||||||
props
|
tag_name.to_string(),
|
||||||
},
|
json!({
|
||||||
required: {
|
"type": "string",
|
||||||
let mut required = Set::new();
|
"const": variant
|
||||||
required.insert(tag_name.to_owned());
|
}),
|
||||||
required
|
);
|
||||||
},
|
}
|
||||||
additional_properties: deny_unknown_fields.then(|| Box::new(false.into())),
|
|
||||||
..Default::default()
|
if let Some(required) = obj
|
||||||
})),
|
.entry("required")
|
||||||
..SchemaObject::default()
|
.or_insert(Value::Array(Vec::new()))
|
||||||
})
|
.as_array_mut()
|
||||||
|
{
|
||||||
|
required.insert(0, tag_name.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if deny_unknown_fields && is_unit {
|
||||||
|
obj.entry("additionalProperties").or_insert(false.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_object_property<T: ?Sized + JsonSchema>(
|
pub fn insert_object_property<T: ?Sized + JsonSchema>(
|
||||||
obj: &mut ObjectValidation,
|
schema: &mut Schema,
|
||||||
key: &str,
|
key: &str,
|
||||||
has_default: bool,
|
has_default: bool,
|
||||||
required: bool,
|
required: bool,
|
||||||
schema: Schema,
|
sub_schema: Schema,
|
||||||
) {
|
) {
|
||||||
obj.properties.insert(key.to_owned(), schema);
|
let obj = schema.ensure_object();
|
||||||
|
if let Some(properties) = obj
|
||||||
|
.entry("properties")
|
||||||
|
.or_insert(Value::Object(Map::new()))
|
||||||
|
.as_object_mut()
|
||||||
|
{
|
||||||
|
properties.insert(key.to_owned(), sub_schema.into());
|
||||||
|
}
|
||||||
|
|
||||||
if !has_default && (required || !T::_schemars_private_is_option()) {
|
if !has_default && (required || !T::_schemars_private_is_option()) {
|
||||||
obj.required.insert(key.to_owned());
|
if let Some(req) = obj
|
||||||
|
.entry("required")
|
||||||
|
.or_insert(Value::Array(Vec::new()))
|
||||||
|
.as_array_mut()
|
||||||
|
{
|
||||||
|
req.push(key.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod metadata {
|
pub fn insert_validation_property(
|
||||||
use crate::Schema;
|
schema: &mut Schema,
|
||||||
use serde_json::Value;
|
required_type: &str,
|
||||||
|
key: &str,
|
||||||
|
value: impl Into<Value>,
|
||||||
|
) {
|
||||||
|
if schema.has_type(required_type) || (required_type == "number" && schema.has_type("integer")) {
|
||||||
|
schema.ensure_object().insert(key.to_owned(), value.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! add_metadata_fn {
|
pub fn append_required(schema: &mut Schema, key: &str) {
|
||||||
($method:ident, $name:ident, $ty:ty) => {
|
if schema.has_type("object") {
|
||||||
pub fn $method(schema: Schema, $name: impl Into<$ty>) -> Schema {
|
if let Value::Array(array) = schema
|
||||||
let value = $name.into();
|
.ensure_object()
|
||||||
if value == <$ty>::default() {
|
.entry("required")
|
||||||
schema
|
.or_insert(Value::Array(Vec::new()))
|
||||||
} else {
|
{
|
||||||
let mut schema_obj = schema.into_object();
|
let value = Value::from(key);
|
||||||
schema_obj.metadata().$name = value.into();
|
if !array.contains(&value) {
|
||||||
Schema::Object(schema_obj)
|
array.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_inner_validation(schema: &mut Schema, f: fn(&mut Schema) -> ()) {
|
||||||
|
if let Some(inner_schema) = schema
|
||||||
|
.as_object_mut()
|
||||||
|
.and_then(|o| o.get_mut("items"))
|
||||||
|
.and_then(|i| <&mut Schema>::try_from(i).ok())
|
||||||
|
{
|
||||||
|
f(inner_schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flatten(schema: &mut Schema, other: Schema) {
|
||||||
|
if let Value::Object(obj2) = other.to_value() {
|
||||||
|
let obj1 = schema.ensure_object();
|
||||||
|
|
||||||
|
for (key, value2) in obj2 {
|
||||||
|
match obj1.entry(key) {
|
||||||
|
Entry::Vacant(vacant) => {
|
||||||
|
vacant.insert(value2);
|
||||||
|
}
|
||||||
|
Entry::Occupied(mut occupied) => {
|
||||||
|
match occupied.key().as_str() {
|
||||||
|
// This special "type" handling can probably be removed once the enum variant `with`/`schema_with` behaviour is fixed
|
||||||
|
"type" => match (occupied.get_mut(), value2) {
|
||||||
|
(Value::Array(a1), Value::Array(mut a2)) => {
|
||||||
|
a2.retain(|v2| !a1.contains(v2));
|
||||||
|
a1.extend(a2);
|
||||||
|
}
|
||||||
|
(v1, Value::Array(mut a2)) => {
|
||||||
|
if !a2.contains(v1) {
|
||||||
|
a2.push(std::mem::take(v1));
|
||||||
|
*occupied.get_mut() = Value::Array(a2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Array(a1), v2) => {
|
||||||
|
if !a1.contains(&v2) {
|
||||||
|
a1.push(v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(v1, v2) => {
|
||||||
|
if v1 != &v2 {
|
||||||
|
*occupied.get_mut() =
|
||||||
|
Value::Array(vec![std::mem::take(v1), v2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required" => {
|
||||||
|
if let Value::Array(a1) = occupied.into_mut() {
|
||||||
|
if let Value::Array(a2) = value2 {
|
||||||
|
a1.extend(a2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"properties" | "patternProperties" => {
|
||||||
|
if let Value::Object(o1) = occupied.into_mut() {
|
||||||
|
if let Value::Object(o2) = value2 {
|
||||||
|
o1.extend(o2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// leave the original value as it is (don't modify `schema`)
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
|
||||||
add_metadata_fn!(add_description, description, String);
|
|
||||||
add_metadata_fn!(add_id, id, String);
|
|
||||||
add_metadata_fn!(add_title, title, String);
|
|
||||||
add_metadata_fn!(add_deprecated, deprecated, bool);
|
|
||||||
add_metadata_fn!(add_read_only, read_only, bool);
|
|
||||||
add_metadata_fn!(add_write_only, write_only, bool);
|
|
||||||
add_metadata_fn!(add_default, default, Option<Value>);
|
|
||||||
|
|
||||||
pub fn add_examples<I: IntoIterator<Item = Value>>(schema: Schema, examples: I) -> Schema {
|
|
||||||
let mut schema_obj = schema.into_object();
|
|
||||||
schema_obj.metadata().examples.extend(examples);
|
|
||||||
Schema::Object(schema_obj)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,180 +0,0 @@
|
||||||
use crate::schema::*;
|
|
||||||
use crate::{Map, Set};
|
|
||||||
|
|
||||||
impl Schema {
|
|
||||||
/// This function is only public for use by schemars_derive.
|
|
||||||
///
|
|
||||||
/// It should not be considered part of the public API.
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn flatten(self, other: Self) -> Schema {
|
|
||||||
if is_null_type(&self) {
|
|
||||||
return other;
|
|
||||||
} else if is_null_type(&other) {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
let s1: SchemaObject = self.into();
|
|
||||||
let s2: SchemaObject = other.into();
|
|
||||||
Schema::Object(s1.merge(s2))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait Merge: Sized {
|
|
||||||
fn merge(self, other: Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_merge {
|
|
||||||
($ty:ident { merge: $($merge_field:ident)*, or: $($or_field:ident)*, }) => {
|
|
||||||
impl Merge for $ty {
|
|
||||||
fn merge(self, other: Self) -> Self {
|
|
||||||
$ty {
|
|
||||||
$($merge_field: self.$merge_field.merge(other.$merge_field),)*
|
|
||||||
$($or_field: self.$or_field.or(other.$or_field),)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
($ty:ident { or: $($or_field:ident)*, }) => {
|
|
||||||
impl_merge!( $ty { merge: , or: $($or_field)*, });
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// For ObjectValidation::additional_properties.
|
|
||||||
impl Merge for Option<Box<Schema>> {
|
|
||||||
fn merge(self, other: Self) -> Self {
|
|
||||||
match (self.map(|x| *x), other.map(|x| *x)) {
|
|
||||||
// Perfer permissive schemas.
|
|
||||||
(Some(Schema::Bool(true)), _) => Some(Box::new(true.into())),
|
|
||||||
(_, Some(Schema::Bool(true))) => Some(Box::new(true.into())),
|
|
||||||
(None, _) => None,
|
|
||||||
(_, None) => None,
|
|
||||||
|
|
||||||
// Merge if we have two non-trivial schemas.
|
|
||||||
(Some(Schema::Object(s1)), Some(Schema::Object(s2))) => {
|
|
||||||
Some(Box::new(Schema::Object(s1.merge(s2))))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perfer the more permissive schema.
|
|
||||||
(Some(s1 @ Schema::Object(_)), Some(Schema::Bool(false))) => Some(Box::new(s1)),
|
|
||||||
(Some(Schema::Bool(false)), Some(s2 @ Schema::Object(_))) => Some(Box::new(s2)),
|
|
||||||
|
|
||||||
// Default to the null schema.
|
|
||||||
(Some(Schema::Bool(false)), Some(Schema::Bool(false))) => Some(Box::new(false.into())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_merge!(SchemaObject {
|
|
||||||
merge: extensions instance_type enum_values
|
|
||||||
metadata subschemas number string array object,
|
|
||||||
or: format const_value reference,
|
|
||||||
});
|
|
||||||
|
|
||||||
impl Merge for Metadata {
|
|
||||||
fn merge(self, other: Self) -> Self {
|
|
||||||
Metadata {
|
|
||||||
id: self.id.or(other.id),
|
|
||||||
title: self.title.or(other.title),
|
|
||||||
description: self.description.or(other.description),
|
|
||||||
default: self.default.or(other.default),
|
|
||||||
deprecated: self.deprecated || other.deprecated,
|
|
||||||
read_only: self.read_only || other.read_only,
|
|
||||||
write_only: self.write_only || other.write_only,
|
|
||||||
examples: self.examples.merge(other.examples),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_merge!(SubschemaValidation {
|
|
||||||
or: all_of any_of one_of not if_schema then_schema else_schema,
|
|
||||||
});
|
|
||||||
|
|
||||||
impl_merge!(NumberValidation {
|
|
||||||
or: multiple_of maximum exclusive_maximum minimum exclusive_minimum,
|
|
||||||
});
|
|
||||||
|
|
||||||
impl_merge!(StringValidation {
|
|
||||||
or: max_length min_length pattern,
|
|
||||||
});
|
|
||||||
|
|
||||||
impl_merge!(ArrayValidation {
|
|
||||||
or: items additional_items max_items min_items unique_items contains,
|
|
||||||
});
|
|
||||||
|
|
||||||
impl_merge!(ObjectValidation {
|
|
||||||
merge: required properties pattern_properties additional_properties,
|
|
||||||
or: max_properties min_properties property_names,
|
|
||||||
});
|
|
||||||
|
|
||||||
impl<T: Merge> Merge for Option<T> {
|
|
||||||
fn merge(self, other: Self) -> Self {
|
|
||||||
match (self, other) {
|
|
||||||
(Some(x), Some(y)) => Some(x.merge(y)),
|
|
||||||
(None, y) => y,
|
|
||||||
(x, None) => x,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Merge> Merge for Box<T> {
|
|
||||||
fn merge(mut self, other: Self) -> Self {
|
|
||||||
*self = (*self).merge(*other);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Merge for Vec<T> {
|
|
||||||
fn merge(mut self, other: Self) -> Self {
|
|
||||||
self.extend(other);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K, V> Merge for Map<K, V>
|
|
||||||
where
|
|
||||||
K: std::hash::Hash + Eq + Ord,
|
|
||||||
{
|
|
||||||
fn merge(mut self, other: Self) -> Self {
|
|
||||||
self.extend(other);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Ord> Merge for Set<T> {
|
|
||||||
fn merge(mut self, other: Self) -> Self {
|
|
||||||
self.extend(other);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Merge for SingleOrVec<InstanceType> {
|
|
||||||
fn merge(self, other: Self) -> Self {
|
|
||||||
if self == other {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
let mut vec = match (self, other) {
|
|
||||||
(SingleOrVec::Vec(v1), SingleOrVec::Vec(v2)) => v1.merge(v2),
|
|
||||||
(SingleOrVec::Vec(mut v), SingleOrVec::Single(s))
|
|
||||||
| (SingleOrVec::Single(s), SingleOrVec::Vec(mut v)) => {
|
|
||||||
v.push(*s);
|
|
||||||
v
|
|
||||||
}
|
|
||||||
(SingleOrVec::Single(s1), SingleOrVec::Single(s2)) => vec![*s1, *s2],
|
|
||||||
};
|
|
||||||
vec.sort();
|
|
||||||
vec.dedup();
|
|
||||||
SingleOrVec::Vec(vec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_null_type(schema: &Schema) -> bool {
|
|
||||||
let s = match schema {
|
|
||||||
Schema::Object(s) => s,
|
|
||||||
_ => return false,
|
|
||||||
};
|
|
||||||
let instance_type = match &s.instance_type {
|
|
||||||
Some(SingleOrVec::Single(t)) => t,
|
|
||||||
_ => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
**instance_type == InstanceType::Null
|
|
||||||
}
|
|
|
@ -7,41 +7,45 @@ There are two main types in this module:
|
||||||
* [`SchemaGenerator`], which manages the generation of a schema document.
|
* [`SchemaGenerator`], which manages the generation of a schema document.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::schema::*;
|
use crate::Schema;
|
||||||
use crate::{visit::*, JsonSchema, Map};
|
use crate::{transform::*, JsonSchema};
|
||||||
use dyn_clone::DynClone;
|
use dyn_clone::DynClone;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::borrow::Cow;
|
use serde_json::{Map, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::{any::Any, collections::HashSet, fmt::Debug};
|
use std::{any::Any, fmt::Debug};
|
||||||
|
|
||||||
|
type CowStr = std::borrow::Cow<'static, str>;
|
||||||
|
|
||||||
/// Settings to customize how Schemas are generated.
|
/// Settings to customize how Schemas are generated.
|
||||||
///
|
///
|
||||||
/// The default settings currently conform to [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
||||||
/// If you require your generated schemas to conform to draft 7, consider using the [`draft07`](#method.draft07) method.
|
/// If you rely on generated schemas conforming to draft 2020-12, consider using the [`SchemaSettings::draft2020_12()`] method.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct SchemaSettings {
|
pub struct SchemaSettings {
|
||||||
/// If `true`, schemas for [`Option<T>`](Option) will include a `nullable` property.
|
/// If `true`, schemas for [`Option<T>`] will include a `nullable` property.
|
||||||
///
|
///
|
||||||
/// This is not part of the JSON Schema spec, but is used in Swagger/OpenAPI schemas.
|
/// This is not part of the JSON Schema spec, but is used in Swagger/OpenAPI schemas.
|
||||||
///
|
///
|
||||||
/// Defaults to `false`.
|
/// Defaults to `false`.
|
||||||
pub option_nullable: bool,
|
pub option_nullable: bool,
|
||||||
/// If `true`, schemas for [`Option<T>`](Option) will have `null` added to their [`type`](../schema/struct.SchemaObject.html#structfield.instance_type).
|
/// If `true`, schemas for [`Option<T>`] will have `null` added to their `type` property.
|
||||||
///
|
///
|
||||||
/// Defaults to `true`.
|
/// Defaults to `true`.
|
||||||
pub option_add_null_type: bool,
|
pub option_add_null_type: bool,
|
||||||
/// A JSON pointer to the expected location of referenceable subschemas within the resulting root schema.
|
/// A JSON pointer to the expected location of referenceable subschemas within the resulting root schema.
|
||||||
///
|
///
|
||||||
/// Defaults to `"#/definitions/"`.
|
/// A single leading `#` and/or single trailing `/` are ignored.
|
||||||
|
///
|
||||||
|
/// Defaults to `"/$defs"`.
|
||||||
pub definitions_path: String,
|
pub definitions_path: String,
|
||||||
/// The URI of the meta-schema describing the structure of the generated schemas.
|
/// The URI of the meta-schema describing the structure of the generated schemas.
|
||||||
///
|
///
|
||||||
/// Defaults to `"http://json-schema.org/draft-07/schema#"`.
|
/// Defaults to `"https://json-schema.org/draft/2020-12/schema"`.
|
||||||
pub meta_schema: Option<String>,
|
pub meta_schema: Option<String>,
|
||||||
/// A list of visitors that get applied to all generated root schemas.
|
/// A list of [`Transform`]s that get applied to generated root schemas.
|
||||||
pub visitors: Vec<Box<dyn GenVisitor>>,
|
pub transforms: Vec<Box<dyn GenTransform>>,
|
||||||
/// Inline all subschemas instead of using references.
|
/// Inline all subschemas instead of using references.
|
||||||
///
|
///
|
||||||
/// Some references may still be generated in schemas for recursive types.
|
/// Some references may still be generated in schemas for recursive types.
|
||||||
|
@ -51,54 +55,68 @@ pub struct SchemaSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SchemaSettings {
|
impl Default for SchemaSettings {
|
||||||
|
/// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added.
|
||||||
|
/// If you rely on generated schemas conforming to draft 2020-12, consider using the [`SchemaSettings::draft2020_12()`] method.
|
||||||
fn default() -> SchemaSettings {
|
fn default() -> SchemaSettings {
|
||||||
SchemaSettings::draft07()
|
SchemaSettings::draft2020_12()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchemaSettings {
|
impl SchemaSettings {
|
||||||
/// Creates `SchemaSettings` that conform to [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7).
|
/// Creates `SchemaSettings` that conform to [JSON Schema Draft 7](https://json-schema.org/specification-links#draft-7).
|
||||||
pub fn draft07() -> SchemaSettings {
|
pub fn draft07() -> SchemaSettings {
|
||||||
SchemaSettings {
|
SchemaSettings {
|
||||||
option_nullable: false,
|
option_nullable: false,
|
||||||
option_add_null_type: true,
|
option_add_null_type: true,
|
||||||
definitions_path: "#/definitions/".to_owned(),
|
definitions_path: "/definitions".to_owned(),
|
||||||
meta_schema: Some("http://json-schema.org/draft-07/schema#".to_owned()),
|
meta_schema: Some("http://json-schema.org/draft-07/schema#".to_owned()),
|
||||||
visitors: vec![Box::new(RemoveRefSiblings)],
|
transforms: vec![Box::new(RemoveRefSiblings), Box::new(ReplacePrefixItems)],
|
||||||
inline_subschemas: false,
|
inline_subschemas: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates `SchemaSettings` that conform to [JSON Schema 2019-09](https://json-schema.org/specification-links.html#2019-09-formerly-known-as-draft-8).
|
/// Creates `SchemaSettings` that conform to [JSON Schema 2019-09](https://json-schema.org/specification-links#draft-2019-09-(formerly-known-as-draft-8)).
|
||||||
pub fn draft2019_09() -> SchemaSettings {
|
pub fn draft2019_09() -> SchemaSettings {
|
||||||
SchemaSettings {
|
SchemaSettings {
|
||||||
option_nullable: false,
|
option_nullable: false,
|
||||||
option_add_null_type: true,
|
option_add_null_type: true,
|
||||||
definitions_path: "#/definitions/".to_owned(),
|
definitions_path: "/$defs".to_owned(),
|
||||||
meta_schema: Some("https://json-schema.org/draft/2019-09/schema".to_owned()),
|
meta_schema: Some("https://json-schema.org/draft/2019-09/schema".to_owned()),
|
||||||
visitors: Vec::default(),
|
transforms: vec![Box::new(ReplacePrefixItems)],
|
||||||
inline_subschemas: false,
|
inline_subschemas: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates `SchemaSettings` that conform to [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject).
|
/// Creates `SchemaSettings` that conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12).
|
||||||
|
pub fn draft2020_12() -> SchemaSettings {
|
||||||
|
SchemaSettings {
|
||||||
|
option_nullable: false,
|
||||||
|
option_add_null_type: true,
|
||||||
|
definitions_path: "/$defs".to_owned(),
|
||||||
|
meta_schema: Some("https://json-schema.org/draft/2020-12/schema".to_owned()),
|
||||||
|
transforms: Vec::new(),
|
||||||
|
inline_subschemas: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates `SchemaSettings` that conform to [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schema).
|
||||||
pub fn openapi3() -> SchemaSettings {
|
pub fn openapi3() -> SchemaSettings {
|
||||||
SchemaSettings {
|
SchemaSettings {
|
||||||
option_nullable: true,
|
option_nullable: true,
|
||||||
option_add_null_type: false,
|
option_add_null_type: false,
|
||||||
definitions_path: "#/components/schemas/".to_owned(),
|
definitions_path: "/components/schemas".to_owned(),
|
||||||
meta_schema: Some(
|
meta_schema: Some(
|
||||||
"https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema"
|
"https://spec.openapis.org/oas/3.0/schema/2021-09-28#/definitions/Schema"
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
),
|
),
|
||||||
visitors: vec![
|
transforms: vec![
|
||||||
Box::new(RemoveRefSiblings),
|
Box::new(RemoveRefSiblings),
|
||||||
Box::new(ReplaceBoolSchemas {
|
Box::new(ReplaceBoolSchemas {
|
||||||
skip_additional_properties: true,
|
skip_additional_properties: true,
|
||||||
}),
|
}),
|
||||||
Box::new(SetSingleExample {
|
Box::new(SetSingleExample),
|
||||||
retain_examples: false,
|
Box::new(ReplaceConstValue),
|
||||||
}),
|
Box::new(ReplacePrefixItems),
|
||||||
],
|
],
|
||||||
inline_subschemas: false,
|
inline_subschemas: false,
|
||||||
}
|
}
|
||||||
|
@ -121,9 +139,9 @@ impl SchemaSettings {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the given visitor to the list of [visitors](SchemaSettings::visitors) for these `SchemaSettings`.
|
/// Appends the given transform to the list of [transforms](SchemaSettings::transforms) for these `SchemaSettings`.
|
||||||
pub fn with_visitor(mut self, visitor: impl Visitor + Debug + Clone + 'static) -> Self {
|
pub fn with_transform(mut self, transform: impl Transform + Clone + 'static + Send) -> Self {
|
||||||
self.visitors.push(Box::new(visitor));
|
self.transforms.push(Box::new(transform));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +155,7 @@ impl SchemaSettings {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// use schemars::{JsonSchema, gen::SchemaGenerator};
|
/// use schemars::{JsonSchema, SchemaGenerator};
|
||||||
///
|
///
|
||||||
/// #[derive(JsonSchema)]
|
/// #[derive(JsonSchema)]
|
||||||
/// struct MyStruct {
|
/// struct MyStruct {
|
||||||
|
@ -150,10 +168,10 @@ impl SchemaSettings {
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct SchemaGenerator {
|
pub struct SchemaGenerator {
|
||||||
settings: SchemaSettings,
|
settings: SchemaSettings,
|
||||||
definitions: Map<String, Schema>,
|
definitions: Map<String, Value>,
|
||||||
pending_schema_ids: HashSet<Cow<'static, str>>,
|
pending_schema_ids: HashSet<CowStr>,
|
||||||
schema_id_to_name: HashMap<Cow<'static, str>, String>,
|
schema_id_to_name: HashMap<CowStr, CowStr>,
|
||||||
used_schema_names: HashSet<String>,
|
used_schema_names: HashSet<CowStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for SchemaGenerator {
|
impl Clone for SchemaGenerator {
|
||||||
|
@ -187,7 +205,7 @@ impl SchemaGenerator {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// use schemars::gen::SchemaGenerator;
|
/// use schemars::SchemaGenerator;
|
||||||
///
|
///
|
||||||
/// let gen = SchemaGenerator::default();
|
/// let gen = SchemaGenerator::default();
|
||||||
/// let settings = gen.settings();
|
/// let settings = gen.settings();
|
||||||
|
@ -198,29 +216,16 @@ impl SchemaGenerator {
|
||||||
&self.settings
|
&self.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated = "This method no longer has any effect."]
|
|
||||||
pub fn make_extensible(&self, _schema: &mut SchemaObject) {}
|
|
||||||
|
|
||||||
#[deprecated = "Use `Schema::Bool(true)` instead"]
|
|
||||||
pub fn schema_for_any(&self) -> Schema {
|
|
||||||
Schema::Bool(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deprecated = "Use `Schema::Bool(false)` instead"]
|
|
||||||
pub fn schema_for_none(&self) -> Schema {
|
|
||||||
Schema::Bool(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates a JSON Schema for the type `T`, and returns either the schema itself or a `$ref` schema referencing `T`'s schema.
|
/// Generates a JSON Schema for the type `T`, and returns either the schema itself or a `$ref` schema referencing `T`'s schema.
|
||||||
///
|
///
|
||||||
/// If `T` is [referenceable](JsonSchema::is_referenceable), this will add `T`'s schema to this generator's definitions, and
|
/// If `T` is not [inlined](JsonSchema::always_inline_schema), this will add `T`'s schema to this generator's definitions, and
|
||||||
/// return a `$ref` schema referencing that schema. Otherwise, this method behaves identically to [`JsonSchema::json_schema`].
|
/// return a `$ref` schema referencing that schema. Otherwise, this method behaves identically to [`JsonSchema::json_schema`].
|
||||||
///
|
///
|
||||||
/// If `T`'s schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
|
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will
|
||||||
/// add them to the `SchemaGenerator`'s schema definitions.
|
/// add them to the `SchemaGenerator`'s schema definitions.
|
||||||
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
||||||
let id = T::schema_id();
|
let id = T::schema_id();
|
||||||
let return_ref = T::is_referenceable()
|
let return_ref = !T::always_inline_schema()
|
||||||
&& (!self.settings.inline_subschemas || self.pending_schema_ids.contains(&id));
|
&& (!self.settings.inline_subschemas || self.pending_schema_ids.contains(&id));
|
||||||
|
|
||||||
if return_ref {
|
if return_ref {
|
||||||
|
@ -228,11 +233,11 @@ impl SchemaGenerator {
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => {
|
None => {
|
||||||
let base_name = T::schema_name();
|
let base_name = T::schema_name();
|
||||||
let mut name = String::new();
|
let mut name = CowStr::Borrowed("");
|
||||||
|
|
||||||
if self.used_schema_names.contains(&base_name) {
|
if self.used_schema_names.contains(base_name.as_ref()) {
|
||||||
for i in 2.. {
|
for i in 2.. {
|
||||||
name = format!("{}{}", base_name, i);
|
name = format!("{}{}", base_name, i).into();
|
||||||
if !self.used_schema_names.contains(&name) {
|
if !self.used_schema_names.contains(&name) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -247,8 +252,8 @@ impl SchemaGenerator {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let reference = format!("{}{}", self.settings.definitions_path, name);
|
let reference = format!("#{}/{}", self.definitions_path_stripped(), name);
|
||||||
if !self.definitions.contains_key(&name) {
|
if !self.definitions.contains_key(name.as_ref()) {
|
||||||
self.insert_new_subschema_for::<T>(name, id);
|
self.insert_new_subschema_for::<T>(name, id);
|
||||||
}
|
}
|
||||||
Schema::new_ref(reference)
|
Schema::new_ref(reference)
|
||||||
|
@ -257,207 +262,165 @@ impl SchemaGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_new_subschema_for<T: ?Sized + JsonSchema>(
|
fn insert_new_subschema_for<T: ?Sized + JsonSchema>(&mut self, name: CowStr, id: CowStr) {
|
||||||
&mut self,
|
let dummy = false.into();
|
||||||
name: String,
|
|
||||||
id: Cow<'static, str>,
|
|
||||||
) {
|
|
||||||
let dummy = Schema::Bool(false);
|
|
||||||
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
|
// insert into definitions BEFORE calling json_schema to avoid infinite recursion
|
||||||
self.definitions.insert(name.clone(), dummy);
|
self.definitions.insert(name.clone().into(), dummy);
|
||||||
|
|
||||||
let schema = self.json_schema_internal::<T>(id);
|
let schema = self.json_schema_internal::<T>(id);
|
||||||
|
|
||||||
self.definitions.insert(name, schema);
|
self.definitions.insert(name.into(), schema.to_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the collection of all [referenceable](JsonSchema::is_referenceable) schemas that have been generated.
|
/// Borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated.
|
||||||
///
|
///
|
||||||
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
||||||
/// themselves.
|
/// themselves.
|
||||||
pub fn definitions(&self) -> &Map<String, Schema> {
|
pub fn definitions(&self) -> &Map<String, Value> {
|
||||||
&self.definitions
|
&self.definitions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutably borrows the collection of all [referenceable](JsonSchema::is_referenceable) schemas that have been generated.
|
/// Mutably borrows the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated.
|
||||||
///
|
///
|
||||||
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
||||||
/// themselves.
|
/// themselves.
|
||||||
pub fn definitions_mut(&mut self) -> &mut Map<String, Schema> {
|
pub fn definitions_mut(&mut self) -> &mut Map<String, Value> {
|
||||||
&mut self.definitions
|
&mut self.definitions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the collection of all [referenceable](JsonSchema::is_referenceable) schemas that have been generated,
|
/// Returns the collection of all [non-inlined](JsonSchema::always_inline_schema) schemas that have been generated,
|
||||||
/// leaving an empty map in its place.
|
/// leaving an empty `Map` in its place.
|
||||||
///
|
///
|
||||||
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
/// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the values are the schemas
|
||||||
/// themselves.
|
/// themselves.
|
||||||
pub fn take_definitions(&mut self) -> Map<String, Schema> {
|
pub fn take_definitions(&mut self) -> Map<String, Value> {
|
||||||
std::mem::take(&mut self.definitions)
|
std::mem::take(&mut self.definitions)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over the [visitors](SchemaSettings::visitors) being used by this `SchemaGenerator`.
|
/// Returns an iterator over the [transforms](SchemaSettings::transforms) being used by this `SchemaGenerator`.
|
||||||
pub fn visitors_mut(&mut self) -> impl Iterator<Item = &mut dyn GenVisitor> {
|
pub fn transforms_mut(&mut self) -> impl Iterator<Item = &mut dyn GenTransform> {
|
||||||
self.settings.visitors.iter_mut().map(|v| v.as_mut())
|
self.settings.transforms.iter_mut().map(|v| v.as_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a root JSON Schema for the type `T`.
|
/// Generates a JSON Schema for the type `T`.
|
||||||
///
|
///
|
||||||
/// If `T`'s schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
|
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will
|
||||||
/// add them to the `SchemaGenerator`'s schema definitions and include them in the returned `SchemaObject`'s
|
/// include them in the returned `Schema` at the [definitions path](SchemaSettings::definitions_path) (by default `"$defs"`).
|
||||||
/// [`definitions`](../schema/struct.Metadata.html#structfield.definitions)
|
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
|
||||||
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> RootSchema {
|
let mut schema = self.json_schema_internal::<T>(T::schema_id());
|
||||||
let mut schema = self.json_schema_internal::<T>(T::schema_id()).into_object();
|
|
||||||
schema.metadata().title.get_or_insert_with(T::schema_name);
|
|
||||||
let mut root = RootSchema {
|
|
||||||
meta_schema: self.settings.meta_schema.clone(),
|
|
||||||
definitions: self.definitions.clone(),
|
|
||||||
schema,
|
|
||||||
};
|
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
let object = schema.ensure_object();
|
||||||
visitor.visit_root_schema(&mut root)
|
|
||||||
|
object
|
||||||
|
.entry("title")
|
||||||
|
.or_insert_with(|| T::schema_name().into());
|
||||||
|
|
||||||
|
if let Some(meta_schema) = self.settings.meta_schema.as_deref() {
|
||||||
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
root
|
self.add_definitions(object, self.definitions.clone());
|
||||||
|
self.apply_transforms(&mut schema);
|
||||||
|
|
||||||
|
schema
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes `self` and generates a root JSON Schema for the type `T`.
|
/// Consumes `self` and generates a JSON Schema for the type `T`.
|
||||||
///
|
///
|
||||||
/// If `T`'s schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
|
/// If `T`'s schema depends on any [non-inlined](JsonSchema::always_inline_schema) schemas, then this method will
|
||||||
/// include them in the returned `SchemaObject`'s [`definitions`](../schema/struct.Metadata.html#structfield.definitions)
|
/// include them in the returned `Schema` at the [definitions path](SchemaSettings::definitions_path) (by default `"$defs"`).
|
||||||
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> RootSchema {
|
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Schema {
|
||||||
let mut schema = self.json_schema_internal::<T>(T::schema_id()).into_object();
|
let mut schema = self.json_schema_internal::<T>(T::schema_id());
|
||||||
schema.metadata().title.get_or_insert_with(T::schema_name);
|
|
||||||
let mut root = RootSchema {
|
|
||||||
meta_schema: self.settings.meta_schema,
|
|
||||||
definitions: self.definitions,
|
|
||||||
schema,
|
|
||||||
};
|
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
let object = schema.ensure_object();
|
||||||
visitor.visit_root_schema(&mut root)
|
|
||||||
|
object
|
||||||
|
.entry("title")
|
||||||
|
.or_insert_with(|| T::schema_name().into());
|
||||||
|
|
||||||
|
if let Some(meta_schema) = std::mem::take(&mut self.settings.meta_schema) {
|
||||||
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
root
|
let definitions = self.take_definitions();
|
||||||
|
self.add_definitions(object, definitions);
|
||||||
|
self.apply_transforms(&mut schema);
|
||||||
|
|
||||||
|
schema
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a root JSON Schema for the given example value.
|
/// Generates a JSON Schema for the given example value.
|
||||||
///
|
///
|
||||||
/// If the value implements [`JsonSchema`](crate::JsonSchema), then prefer using the [`root_schema_for()`](Self::root_schema_for())
|
/// If the value implements [`JsonSchema`](crate::JsonSchema), then prefer using the [`root_schema_for()`](Self::root_schema_for())
|
||||||
/// function which will generally produce a more precise schema, particularly when the value contains any enums.
|
/// function which will generally produce a more precise schema, particularly when the value contains any enums.
|
||||||
|
///
|
||||||
|
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
|
||||||
pub fn root_schema_for_value<T: ?Sized + Serialize>(
|
pub fn root_schema_for_value<T: ?Sized + Serialize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<RootSchema, serde_json::Error> {
|
) -> Result<Schema, serde_json::Error> {
|
||||||
let mut schema = value
|
let mut schema = value.serialize(crate::ser::Serializer {
|
||||||
.serialize(crate::ser::Serializer {
|
gen: self,
|
||||||
gen: self,
|
include_title: true,
|
||||||
include_title: true,
|
})?;
|
||||||
})?
|
|
||||||
.into_object();
|
let object = schema.ensure_object();
|
||||||
|
|
||||||
if let Ok(example) = serde_json::to_value(value) {
|
if let Ok(example) = serde_json::to_value(value) {
|
||||||
schema.metadata().examples.push(example);
|
object.insert("examples".into(), vec![example].into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut root = RootSchema {
|
if let Some(meta_schema) = self.settings.meta_schema.as_deref() {
|
||||||
meta_schema: self.settings.meta_schema.clone(),
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
definitions: self.definitions.clone(),
|
|
||||||
schema,
|
|
||||||
};
|
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
|
||||||
visitor.visit_root_schema(&mut root)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(root)
|
self.add_definitions(object, self.definitions.clone());
|
||||||
|
self.apply_transforms(&mut schema);
|
||||||
|
|
||||||
|
Ok(schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes `self` and generates a root JSON Schema for the given example value.
|
/// Consumes `self` and generates a JSON Schema for the given example value.
|
||||||
///
|
///
|
||||||
/// If the value implements [`JsonSchema`](crate::JsonSchema), then prefer using the [`into_root_schema_for()!`](Self::into_root_schema_for())
|
/// If the value implements [`JsonSchema`](crate::JsonSchema), then prefer using the [`into_root_schema_for()!`](Self::into_root_schema_for())
|
||||||
/// function which will generally produce a more precise schema, particularly when the value contains any enums.
|
/// function which will generally produce a more precise schema, particularly when the value contains any enums.
|
||||||
|
///
|
||||||
|
/// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`].
|
||||||
pub fn into_root_schema_for_value<T: ?Sized + Serialize>(
|
pub fn into_root_schema_for_value<T: ?Sized + Serialize>(
|
||||||
mut self,
|
mut self,
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<RootSchema, serde_json::Error> {
|
) -> Result<Schema, serde_json::Error> {
|
||||||
let mut schema = value
|
let mut schema = value.serialize(crate::ser::Serializer {
|
||||||
.serialize(crate::ser::Serializer {
|
gen: &mut self,
|
||||||
gen: &mut self,
|
include_title: true,
|
||||||
include_title: true,
|
})?;
|
||||||
})?
|
|
||||||
.into_object();
|
let object = schema.ensure_object();
|
||||||
|
|
||||||
if let Ok(example) = serde_json::to_value(value) {
|
if let Ok(example) = serde_json::to_value(value) {
|
||||||
schema.metadata().examples.push(example);
|
object.insert("examples".into(), vec![example].into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut root = RootSchema {
|
if let Some(meta_schema) = std::mem::take(&mut self.settings.meta_schema) {
|
||||||
meta_schema: self.settings.meta_schema,
|
object.insert("$schema".into(), meta_schema.into());
|
||||||
definitions: self.definitions,
|
|
||||||
schema,
|
|
||||||
};
|
|
||||||
|
|
||||||
for visitor in &mut self.settings.visitors {
|
|
||||||
visitor.visit_root_schema(&mut root)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(root)
|
let definitions = self.take_definitions();
|
||||||
|
self.add_definitions(object, definitions);
|
||||||
|
self.apply_transforms(&mut schema);
|
||||||
|
|
||||||
|
Ok(schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attemps to find the schema that the given `schema` is referencing.
|
fn json_schema_internal<T: ?Sized + JsonSchema>(&mut self, id: CowStr) -> Schema {
|
||||||
///
|
|
||||||
/// If the given `schema` has a [`$ref`](../schema/struct.SchemaObject.html#structfield.reference) property which refers
|
|
||||||
/// to another schema in `self`'s schema definitions, the referenced schema will be returned. Otherwise, returns `None`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```
|
|
||||||
/// use schemars::{JsonSchema, gen::SchemaGenerator};
|
|
||||||
///
|
|
||||||
/// #[derive(JsonSchema)]
|
|
||||||
/// struct MyStruct {
|
|
||||||
/// foo: i32,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let mut gen = SchemaGenerator::default();
|
|
||||||
/// let ref_schema = gen.subschema_for::<MyStruct>();
|
|
||||||
///
|
|
||||||
/// assert!(ref_schema.is_ref());
|
|
||||||
///
|
|
||||||
/// let dereferenced = gen.dereference(&ref_schema);
|
|
||||||
///
|
|
||||||
/// assert!(dereferenced.is_some());
|
|
||||||
/// assert!(!dereferenced.unwrap().is_ref());
|
|
||||||
/// assert_eq!(dereferenced, gen.definitions().get("MyStruct"));
|
|
||||||
/// ```
|
|
||||||
pub fn dereference<'a>(&'a self, schema: &Schema) -> Option<&'a Schema> {
|
|
||||||
match schema {
|
|
||||||
Schema::Object(SchemaObject {
|
|
||||||
reference: Some(ref schema_ref),
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
let definitions_path = &self.settings().definitions_path;
|
|
||||||
if schema_ref.starts_with(definitions_path) {
|
|
||||||
let name = &schema_ref[definitions_path.len()..];
|
|
||||||
self.definitions.get(name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_schema_internal<T: ?Sized + JsonSchema>(&mut self, id: Cow<'static, str>) -> Schema {
|
|
||||||
struct PendingSchemaState<'a> {
|
struct PendingSchemaState<'a> {
|
||||||
gen: &'a mut SchemaGenerator,
|
gen: &'a mut SchemaGenerator,
|
||||||
id: Cow<'static, str>,
|
id: CowStr,
|
||||||
did_add: bool,
|
did_add: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PendingSchemaState<'a> {
|
impl<'a> PendingSchemaState<'a> {
|
||||||
fn new(gen: &'a mut SchemaGenerator, id: Cow<'static, str>) -> Self {
|
fn new(gen: &'a mut SchemaGenerator, id: CowStr) -> Self {
|
||||||
let did_add = gen.pending_schema_ids.insert(id.clone());
|
let did_add = gen.pending_schema_ids.insert(id.clone());
|
||||||
Self { gen, id, did_add }
|
Self { gen, id, did_add }
|
||||||
}
|
}
|
||||||
|
@ -474,41 +437,157 @@ impl SchemaGenerator {
|
||||||
let pss = PendingSchemaState::new(self, id);
|
let pss = PendingSchemaState::new(self, id);
|
||||||
T::json_schema(pss.gen)
|
T::json_schema(pss.gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_definitions(
|
||||||
|
&mut self,
|
||||||
|
schema_object: &mut Map<String, Value>,
|
||||||
|
mut definitions: Map<String, Value>,
|
||||||
|
) {
|
||||||
|
if definitions.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pointer = self.definitions_path_stripped();
|
||||||
|
let target = match json_pointer_mut(schema_object, pointer, true) {
|
||||||
|
Some(d) => d,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
target.append(&mut definitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_transforms(&mut self, schema: &mut Schema) {
|
||||||
|
for transform in self.transforms_mut() {
|
||||||
|
transform.transform(schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `self.settings.definitions_path` as a plain JSON pointer to the definitions object,
|
||||||
|
/// i.e. without a leading '#' or trailing '/'
|
||||||
|
fn definitions_path_stripped(&self) -> &str {
|
||||||
|
let path = &self.settings.definitions_path;
|
||||||
|
let path = path.strip_prefix('#').unwrap_or(path);
|
||||||
|
path.strip_suffix('/').unwrap_or(path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Visitor](Visitor) which implements additional traits required to be included in a [SchemaSettings].
|
fn json_pointer_mut<'a>(
|
||||||
|
mut object: &'a mut Map<String, Value>,
|
||||||
|
pointer: &str,
|
||||||
|
create_if_missing: bool,
|
||||||
|
) -> Option<&'a mut Map<String, Value>> {
|
||||||
|
let pointer = pointer.strip_prefix('/')?;
|
||||||
|
if pointer.is_empty() {
|
||||||
|
return Some(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
for mut segment in pointer.split('/') {
|
||||||
|
let replaced: String;
|
||||||
|
if segment.contains('~') {
|
||||||
|
replaced = segment.replace("~1", "/").replace("~0", "~");
|
||||||
|
segment = &replaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
use serde_json::map::Entry;
|
||||||
|
let next_value = match object.entry(segment) {
|
||||||
|
Entry::Occupied(o) => o.into_mut(),
|
||||||
|
Entry::Vacant(v) if create_if_missing => v.insert(Value::Object(Map::default())),
|
||||||
|
Entry::Vacant(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
object = next_value.as_object_mut()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [Transform] which implements additional traits required to be included in a [SchemaSettings].
|
||||||
///
|
///
|
||||||
/// You will rarely need to use this trait directly as it is automatically implemented for any type which implements all of:
|
/// You will rarely need to use this trait directly as it is automatically implemented for any type which implements all of:
|
||||||
/// - [`Visitor`]
|
/// - [`Transform`]
|
||||||
/// - [`std::fmt::Debug`]
|
|
||||||
/// - [`std::any::Any`] (implemented for all `'static` types)
|
/// - [`std::any::Any`] (implemented for all `'static` types)
|
||||||
/// - [`std::clone::Clone`]
|
/// - [`std::clone::Clone`]
|
||||||
|
/// - [`std::marker::Send`]
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// use schemars::visit::Visitor;
|
/// use schemars::transform::Transform;
|
||||||
/// use schemars::gen::GenVisitor;
|
/// use schemars::gen::GenTransform;
|
||||||
///
|
///
|
||||||
/// #[derive(Debug, Clone)]
|
/// #[derive(Debug, Clone)]
|
||||||
/// struct MyVisitor;
|
/// struct MyTransform;
|
||||||
///
|
///
|
||||||
/// impl Visitor for MyVisitor { }
|
/// impl Transform for MyTransform {
|
||||||
|
/// fn transform(&mut self, schema: &mut schemars::Schema) {
|
||||||
|
/// todo!()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// let v: &dyn GenVisitor = &MyVisitor;
|
/// let v: &dyn GenTransform = &MyTransform;
|
||||||
/// assert!(v.as_any().is::<MyVisitor>());
|
/// assert!(v.as_any().is::<MyTransform>());
|
||||||
/// ```
|
/// ```
|
||||||
pub trait GenVisitor: Visitor + Debug + DynClone + Any {
|
pub trait GenTransform: Transform + DynClone + Any + Send {
|
||||||
/// Upcasts this visitor into an `Any`, which can be used to inspect and manipulate it as its concrete type.
|
/// Upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as its concrete type.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// To remove a specific transform from an instance of `SchemaSettings`:
|
||||||
|
/// ```
|
||||||
|
/// use schemars::gen::SchemaSettings;
|
||||||
|
/// use schemars::transform::ReplaceBoolSchemas;
|
||||||
|
///
|
||||||
|
/// let mut settings = SchemaSettings::openapi3();
|
||||||
|
/// let original_len = settings.transforms.len();
|
||||||
|
///
|
||||||
|
/// settings
|
||||||
|
/// .transforms
|
||||||
|
/// .retain(|t| !t.as_any().is::<ReplaceBoolSchemas>());
|
||||||
|
///
|
||||||
|
/// assert_eq!(settings.transforms.len(), original_len - 1);
|
||||||
|
/// ```
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
/// Mutably upcasts this transform into an [`Any`], which can be used to inspect and manipulate it as its concrete type.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// To modify a specific transform in an instance of `SchemaSettings`:
|
||||||
|
/// ```
|
||||||
|
/// use schemars::gen::SchemaSettings;
|
||||||
|
/// use schemars::transform::ReplaceBoolSchemas;
|
||||||
|
///
|
||||||
|
/// let mut settings = SchemaSettings::openapi3();
|
||||||
|
/// for t in &mut settings.transforms {
|
||||||
|
/// if let Some(replace_bool_schemas) = t.as_any_mut().downcast_mut::<ReplaceBoolSchemas>() {
|
||||||
|
/// replace_bool_schemas.skip_additional_properties = false;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
dyn_clone::clone_trait_object!(GenVisitor);
|
dyn_clone::clone_trait_object!(GenTransform);
|
||||||
|
|
||||||
impl<T> GenVisitor for T
|
impl<T> GenTransform for T
|
||||||
where
|
where
|
||||||
T: Visitor + Debug + Clone + Any,
|
T: Transform + Clone + Any + Send,
|
||||||
{
|
{
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Box<dyn GenTransform> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self._debug_type_name(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _assert_send() {
|
||||||
|
fn _assert<T: Send>() {}
|
||||||
|
|
||||||
|
_assert::<SchemaSettings>();
|
||||||
|
_assert::<SchemaGenerator>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,24 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::{json_schema, JsonSchema, Schema};
|
||||||
use crate::JsonSchema;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
// Does not require T: JsonSchema.
|
// Does not require T: JsonSchema.
|
||||||
impl<T> JsonSchema for [T; 0] {
|
impl<T> JsonSchema for [T; 0] {
|
||||||
no_ref_schema!();
|
always_inline!();
|
||||||
|
|
||||||
fn schema_name() -> String {
|
fn schema_name() -> Cow<'static, str> {
|
||||||
"EmptyArray".to_owned()
|
"EmptyArray".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema_id() -> Cow<'static, str> {
|
fn schema_id() -> Cow<'static, str> {
|
||||||
Cow::Borrowed("[]")
|
"[]".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
json_schema!({
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
"type": "array",
|
||||||
array: Some(Box::new(ArrayValidation {
|
"maxItems": 0,
|
||||||
max_items: Some(0),
|
})
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,29 +26,23 @@ macro_rules! array_impls {
|
||||||
($($len:tt)+) => {
|
($($len:tt)+) => {
|
||||||
$(
|
$(
|
||||||
impl<T: JsonSchema> JsonSchema for [T; $len] {
|
impl<T: JsonSchema> JsonSchema for [T; $len] {
|
||||||
no_ref_schema!();
|
always_inline!();
|
||||||
|
|
||||||
fn schema_name() -> String {
|
fn schema_name() -> Cow<'static, str> {
|
||||||
format!("Array_size_{}_of_{}", $len, T::schema_name())
|
format!("Array_size_{}_of_{}", $len, T::schema_name()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema_id() -> Cow<'static, str> {
|
fn schema_id() -> Cow<'static, str> {
|
||||||
Cow::Owned(
|
format!("[{}; {}]", $len, T::schema_id()).into()
|
||||||
format!("[{}; {}]", $len, T::schema_id()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
json_schema!({
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
"type": "array",
|
||||||
array: Some(Box::new(ArrayValidation {
|
"items": serde_json::Value::from(gen.subschema_for::<T>()),
|
||||||
items: Some(gen.subschema_for::<T>().into()),
|
"minItems": $len,
|
||||||
max_items: Some($len),
|
"maxItems": $len,
|
||||||
min_items: Some($len),
|
})
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
|
@ -67,40 +55,3 @@ array_impls! {
|
||||||
21 22 23 24 25 26 27 28 29 30
|
21 22 23 24 25 26 27 28 29 30
|
||||||
31 32
|
31 32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::tests::{schema_for, schema_object_for};
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn schema_for_array() {
|
|
||||||
let schema = schema_object_for::<[i32; 8]>();
|
|
||||||
assert_eq!(
|
|
||||||
schema.instance_type,
|
|
||||||
Some(SingleOrVec::from(InstanceType::Array))
|
|
||||||
);
|
|
||||||
let array_validation = schema.array.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
array_validation.items,
|
|
||||||
Some(SingleOrVec::from(schema_for::<i32>()))
|
|
||||||
);
|
|
||||||
assert_eq!(array_validation.max_items, Some(8));
|
|
||||||
assert_eq!(array_validation.min_items, Some(8));
|
|
||||||
}
|
|
||||||
|
|
||||||
// SomeStruct does not implement JsonSchema
|
|
||||||
struct SomeStruct;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn schema_for_empty_array() {
|
|
||||||
let schema = schema_object_for::<[SomeStruct; 0]>();
|
|
||||||
assert_eq!(
|
|
||||||
schema.instance_type,
|
|
||||||
Some(SingleOrVec::from(InstanceType::Array))
|
|
||||||
);
|
|
||||||
let array_validation = schema.array.unwrap();
|
|
||||||
assert_eq!(array_validation.max_items, Some(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
use crate::gen::SchemaGenerator;
|
|
||||||
use crate::schema::*;
|
|
||||||
use crate::JsonSchema;
|
|
||||||
use arrayvec05::{Array, ArrayString, ArrayVec};
|
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
// Do not set maxLength on the schema as that describes length in characters, but we only
|
|
||||||
// know max length in bytes.
|
|
||||||
forward_impl!((<A> JsonSchema for ArrayString<A> where A: Array<Item = u8> + Copy) => String);
|
|
||||||
|
|
||||||
impl<A: Array> JsonSchema for ArrayVec<A>
|
|
||||||
where
|
|
||||||
A::Item: JsonSchema,
|
|
||||||
{
|
|
||||||
no_ref_schema!();
|
|
||||||
|
|
||||||
fn schema_name() -> String {
|
|
||||||
format!(
|
|
||||||
"Array_up_to_size_{}_of_{}",
|
|
||||||
A::CAPACITY,
|
|
||||||
A::Item::schema_name()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
|
||||||
SchemaObject {
|
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
|
||||||
array: Some(Box::new(ArrayValidation {
|
|
||||||
items: Some(gen.subschema_for::<A::Item>().into()),
|
|
||||||
max_items: A::CAPACITY.try_into().ok(),
|
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::gen::SchemaGenerator;
|
use crate::gen::SchemaGenerator;
|
||||||
use crate::schema::*;
|
use crate::{json_schema, JsonSchema, Schema};
|
||||||
use crate::JsonSchema;
|
|
||||||
use arrayvec07::{ArrayString, ArrayVec};
|
use arrayvec07::{ArrayString, ArrayVec};
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
// Do not set maxLength on the schema as that describes length in characters, but we only
|
// Do not set maxLength on the schema as that describes length in characters, but we only
|
||||||
// know max length in bytes.
|
// know max length in bytes.
|
||||||
|
@ -12,22 +10,17 @@ impl<T, const CAP: usize> JsonSchema for ArrayVec<T, CAP>
|
||||||
where
|
where
|
||||||
T: JsonSchema,
|
T: JsonSchema,
|
||||||
{
|
{
|
||||||
no_ref_schema!();
|
always_inline!();
|
||||||
|
|
||||||
fn schema_name() -> String {
|
fn schema_name() -> std::borrow::Cow<'static, str> {
|
||||||
format!("Array_up_to_size_{}_of_{}", CAP, T::schema_name())
|
format!("Array_up_to_size_{}_of_{}", CAP, T::schema_name()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
SchemaObject {
|
json_schema!({
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
"type": "array",
|
||||||
array: Some(Box::new(ArrayValidation {
|
"items": gen.subschema_for::<T>(),
|
||||||
items: Some(gen.subschema_for::<T>().into()),
|
"maxItems": CAP
|
||||||
max_items: CAP.try_into().ok(),
|
})
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
use crate::gen::SchemaGenerator;
|
|
||||||
use crate::schema::*;
|
|
||||||
use crate::JsonSchema;
|
|
||||||
use std::sync::atomic::*;
|
use std::sync::atomic::*;
|
||||||
|
|
||||||
forward_impl!(AtomicBool => bool);
|
forward_impl!(AtomicBool => bool);
|
||||||
|
@ -22,12 +19,12 @@ forward_impl!(AtomicUsize => usize);
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::tests::schema_object_for;
|
use crate::schema_for;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn schema_for_atomics() {
|
fn schema_for_atomics() {
|
||||||
let atomic_schema = schema_object_for::<(
|
let atomic_schema = schema_for!((
|
||||||
AtomicBool,
|
AtomicBool,
|
||||||
AtomicI8,
|
AtomicI8,
|
||||||
AtomicI16,
|
AtomicI16,
|
||||||
|
@ -39,9 +36,8 @@ mod tests {
|
||||||
AtomicU32,
|
AtomicU32,
|
||||||
AtomicU64,
|
AtomicU64,
|
||||||
AtomicUsize,
|
AtomicUsize,
|
||||||
)>();
|
));
|
||||||
let basic_schema =
|
let basic_schema = schema_for!((bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize));
|
||||||
schema_object_for::<(bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize)>();
|
|
||||||
assert_eq!(atomic_schema, basic_schema);
|
assert_eq!(atomic_schema, basic_schema);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
use crate::gen::SchemaGenerator;
|
|
||||||
use crate::schema::*;
|
|
||||||
use crate::JsonSchema;
|
|
||||||
use bytes::{Bytes, BytesMut};
|
|
||||||
|
|
||||||
forward_impl!((JsonSchema for Bytes) => Vec<u8>);
|
|
||||||
forward_impl!((JsonSchema for BytesMut) => Vec<u8>);
|
|
|
@ -1,68 +0,0 @@
|
||||||
use crate::gen::SchemaGenerator;
|
|
||||||
use crate::schema::*;
|
|
||||||
use crate::JsonSchema;
|
|
||||||
use chrono::prelude::*;
|
|
||||||
use serde_json::json;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
impl JsonSchema for Weekday {
|
|
||||||
no_ref_schema!();
|
|
||||||
|
|
||||||
fn schema_name() -> String {
|
|
||||||
"Weekday".to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn schema_id() -> Cow<'static, str> {
|
|
||||||
Cow::Borrowed("chrono::Weekday")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
|
||||||
SchemaObject {
|
|
||||||
instance_type: Some(InstanceType::String.into()),
|
|
||||||
enum_values: Some(vec![
|
|
||||||
json!("Mon"),
|
|
||||||
json!("Tue"),
|
|
||||||
json!("Wed"),
|
|
||||||
json!("Thu"),
|
|
||||||
json!("Fri"),
|
|
||||||
json!("Sat"),
|
|
||||||
json!("Sun"),
|
|
||||||
]),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! formatted_string_impl {
|
|
||||||
($ty:ident, $format:literal) => {
|
|
||||||
formatted_string_impl!($ty, $format, JsonSchema for $ty);
|
|
||||||
};
|
|
||||||
($ty:ident, $format:literal, $($desc:tt)+) => {
|
|
||||||
impl $($desc)+ {
|
|
||||||
no_ref_schema!();
|
|
||||||
|
|
||||||
fn schema_name() -> String {
|
|
||||||
stringify!($ty).to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn schema_id() -> Cow<'static, str> {
|
|
||||||
Cow::Borrowed(stringify!(chrono::$ty))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
|
||||||
SchemaObject {
|
|
||||||
instance_type: Some(InstanceType::String.into()),
|
|
||||||
format: Some($format.to_owned()),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
formatted_string_impl!(NaiveDate, "date");
|
|
||||||
formatted_string_impl!(NaiveDateTime, "partial-date-time");
|
|
||||||
formatted_string_impl!(NaiveTime, "partial-date-time");
|
|
||||||
formatted_string_impl!(DateTime, "date-time", <Tz: TimeZone> JsonSchema for DateTime<Tz>);
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue