├── schemars ├── LICENSE ├── README.md ├── .gitignore ├── tests │ ├── ui.rs │ ├── ui │ │ ├── schema_for_arg_value.rs │ │ ├── repr_missing.rs │ │ ├── repr_non_unit_variant.stderr │ │ ├── repr_non_unit_variant.rs │ │ ├── repr_missing.stderr │ │ ├── invalid_attrs.rs │ │ ├── schema_for_arg_value.stderr │ │ ├── invalid_validation_attrs.rs │ │ ├── invalid_attrs.stderr │ │ └── invalid_validation_attrs.stderr │ ├── expected │ │ ├── regex.json │ │ ├── smol_str.json │ │ ├── struct-unit.json │ │ ├── arrayvec_string.json │ │ ├── schema_with-newtype.json │ │ ├── uuid.json │ │ ├── no-variants.json │ │ ├── schema_with-transparent-newtype.json │ │ ├── struct-newtype.json │ │ ├── bigdecimal03.json │ │ ├── bigdecimal04.json │ │ ├── rust_decimal.json │ │ ├── smallvec.json │ │ ├── validate_newtype.json │ │ ├── enum-repr.json │ │ ├── arrayvec.json │ │ ├── enum-repr-with-attrs.json │ │ ├── url.json │ │ ├── schema-name-const-generics.json │ │ ├── skip_tuple_fields.json │ │ ├── bound.json │ │ ├── enumset.json │ │ ├── schema_with-tuple.json │ │ ├── validate_tuple.json │ │ ├── crate_alias.json │ │ ├── either.json │ │ ├── macro_built_struct.json │ │ ├── struct-tuple.json │ │ ├── schema_with-struct.json │ │ ├── deprecated-struct.json │ │ ├── semver.json │ │ ├── struct-normal.json │ │ ├── inline-subschemas.json │ │ ├── struct-normal-additional-properties.json │ │ ├── skip_struct_fields.json │ │ ├── doc_comments_override.json │ │ ├── indexmap.json │ │ ├── property-name-struct.json │ │ ├── skip_enum_variants.json │ │ ├── bytes.json │ │ ├── enum-unit-doc.json │ │ ├── flatten.json │ │ ├── transparent-struct.json │ │ ├── macro_built_enum.json │ │ ├── examples.json │ │ ├── schema_with-enum-untagged.json │ │ ├── nonzero_ints.json │ │ ├── doc_comments_struct_ref_siblings.json │ │ ├── same_name.json │ │ ├── doc_comments_struct.json │ │ ├── chrono-types.json │ │ ├── schema-name-custom.json │ │ ├── schema-name-default.json │ │ ├── from_json_value.json │ │ ├── enum-simple-internal.json │ │ ├── deprecated-enum.json │ │ ├── enum-simple-internal-duf.json │ │ ├── remote_derive.json │ │ ├── schema_with-enum-internal.json │ │ ├── doc_comments_enum.json │ │ ├── default.json │ │ ├── os_strings.json │ │ ├── duration_and_systemtime.json │ │ ├── remote_derive_generic.json │ │ ├── schema_settings-openapi3.json │ │ ├── inline-subschemas-recursive.json │ │ ├── schema_settings.json │ │ ├── schema_settings-2019_09.json │ │ ├── schema-name-mixed-generics.json │ │ ├── enum-untagged.json │ │ ├── enum-untagged-duf.json │ │ ├── schema_with-enum-external.json │ │ ├── validate_inner.json │ │ ├── from_value_draft07.json │ │ ├── from_value_2019_09.json │ │ ├── from_value_openapi3.json │ │ ├── result.json │ │ ├── range.json │ │ └── schema_with-enum-adjacent-tagged.json │ ├── regex.rs │ ├── smol_str.rs │ ├── bytes.rs │ ├── actual │ │ └── README.md │ ├── either.rs │ ├── smallvec.rs │ ├── uuid.rs │ ├── url.rs │ ├── enumset.rs │ ├── semver.rs │ ├── ffi.rs │ ├── indexmap.rs │ ├── indexmap2.rs │ ├── time.rs │ ├── range.rs │ ├── nonzero_ints.rs │ ├── struct_additional_properties.rs │ ├── result.rs │ ├── decimal.rs │ ├── crate_alias.rs │ ├── chrono.rs │ ├── property_name.rs │ ├── examples.rs │ ├── schema_for_schema.rs │ ├── arrayvec.rs │ ├── same_name.rs │ ├── enum_repr.rs │ ├── dereference.rs │ ├── transparent.rs │ ├── bound.rs │ ├── deprecated.rs │ ├── struct.rs │ ├── validate_inner.rs │ ├── inline_subschemas.rs │ ├── remote_derive.rs │ ├── flatten.rs │ ├── skip.rs │ ├── remote_derive_generic.rs │ ├── schema_settings.rs │ ├── default.rs │ ├── util │ │ └── mod.rs │ ├── macro.rs │ ├── schema_with_struct.rs │ └── schema_name.rs ├── src │ └── json_schema_impls │ │ ├── regex.rs │ │ ├── smol_str.rs │ │ ├── smallvec.rs │ │ ├── bytes.rs │ │ ├── enumset.rs │ │ ├── indexmap.rs │ │ ├── indexmap2.rs │ │ ├── url.rs │ │ ├── uuid08.rs │ │ ├── uuid1.rs │ │ ├── either.rs │ │ ├── semver.rs │ │ ├── arrayvec07.rs │ │ ├── wrapper.rs │ │ ├── serdejson.rs │ │ ├── arrayvec05.rs │ │ ├── decimal.rs │ │ ├── maps.rs │ │ ├── atomic.rs │ │ ├── nonzero_signed.rs │ │ ├── ffi.rs │ │ ├── nonzero_unsigned.rs │ │ ├── time.rs │ │ └── chrono.rs ├── examples │ ├── enum_repr.schema.json │ ├── enum_repr.rs │ ├── main.rs │ ├── from_value.schema.json │ ├── custom_serialization.schema.json │ ├── from_value.rs │ ├── validate.rs │ ├── serde_attrs.rs │ ├── custom_settings.rs │ ├── remote_derive.schema.json │ ├── doc_comments.rs │ ├── schemars_attrs.rs │ ├── serde_attrs.schema.json │ ├── remote_derive.rs │ ├── schemars_attrs.schema.json │ ├── validate.schema.json │ ├── custom_settings.schema.json │ ├── main.schema.json │ ├── custom_serialization.rs │ └── doc_comments.schema.json ├── CHANGELOG.md └── build.rs ├── schemars_derive ├── LICENSE ├── README.md ├── .gitignore ├── Cargo.toml └── src │ ├── regex_syntax.rs │ └── metadata.rs ├── .gitattributes ├── rust-toolchain.toml ├── docs ├── .gitignore ├── 5-examples.md ├── _includes │ ├── examples │ │ ├── enum_repr.schema.json │ │ ├── enum_repr.rs │ │ ├── main.rs │ │ ├── from_value.schema.json │ │ ├── custom_serialization.schema.json │ │ ├── from_value.rs │ │ ├── validate.rs │ │ ├── serde_attrs.rs │ │ ├── custom_settings.rs │ │ ├── remote_derive.schema.json │ │ ├── doc_comments.rs │ │ ├── schemars_attrs.rs │ │ ├── serde_attrs.schema.json │ │ ├── remote_derive.rs │ │ ├── schemars_attrs.schema.json │ │ ├── validate.schema.json │ │ ├── custom_settings.schema.json │ │ ├── main.schema.json │ │ ├── custom_serialization.rs │ │ └── doc_comments.schema.json │ └── example.md ├── _sass │ ├── color_schemes │ │ └── default.scss │ └── custom │ │ └── custom.scss ├── examples │ ├── 1-derive_jsonschema.md │ ├── 4-custom_settings.md │ ├── 3-schemars_attrs.md │ ├── 8-enum_repr.md │ ├── 6-doc_comments.md │ ├── 2-serde_attrs.md │ ├── 9-from_value.md │ ├── 5-remote_derive.md │ └── 7-custom_serialization.md ├── 404.html ├── assets │ └── js │ │ └── search-data.json ├── 1-deriving.md ├── Gemfile ├── index.md ├── 3-generating.md └── 4-features.md ├── .vscode └── settings.json ├── .gitignore ├── renovate.json ├── Cargo.toml ├── update-tests.sh ├── update-examples.sh ├── .github └── workflows │ ├── release.yml │ └── ci.yml └── LICENSE /schemars/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /schemars/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /schemars_derive/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /schemars_derive/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.json text eol=lf 2 | *.stderr text eol=lf 3 | -------------------------------------------------------------------------------- /schemars_derive/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.92.0" 3 | profile = "default" 4 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-cache 4 | .jekyll-metadata 5 | vendor 6 | Gemfile.lock 7 | -------------------------------------------------------------------------------- /schemars/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | /tests/actual/*.json 5 | /tests/expected/README.md -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.check.command": "clippy", 3 | "rust-analyzer.showUnlinkedFileNotification": false 4 | } -------------------------------------------------------------------------------- /schemars/tests/ui.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn ui() { 3 | let t = trybuild::TestCases::new(); 4 | t.compile_fail("tests/ui/*.rs"); 5 | } 6 | -------------------------------------------------------------------------------- /schemars/tests/ui/schema_for_arg_value.rs: -------------------------------------------------------------------------------- 1 | use schemars::schema_for; 2 | 3 | fn main() { 4 | let _schema = schema_for!(123); 5 | } 6 | -------------------------------------------------------------------------------- /schemars/tests/expected/regex.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "String", 4 | "type": "string" 5 | } -------------------------------------------------------------------------------- /schemars/tests/expected/smol_str.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "String", 4 | "type": "string" 5 | } -------------------------------------------------------------------------------- /schemars/tests/expected/struct-unit.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Unit", 4 | "type": "null" 5 | } -------------------------------------------------------------------------------- /docs/5-examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Examples 4 | nav_order: 6 5 | has_children: true 6 | permalink: /examples/ 7 | --- 8 | 9 | # Examples -------------------------------------------------------------------------------- /schemars/tests/expected/arrayvec_string.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "String", 4 | "type": "string" 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-newtype.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Newtype", 4 | "type": "boolean" 5 | } -------------------------------------------------------------------------------- /schemars/tests/ui/repr_missing.rs: -------------------------------------------------------------------------------- 1 | use schemars::JsonSchema_repr; 2 | 3 | #[derive(JsonSchema_repr)] 4 | pub enum Enum { 5 | Unit, 6 | } 7 | 8 | fn main() {} 9 | -------------------------------------------------------------------------------- /schemars/tests/expected/uuid.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Uuid", 4 | "type": "string", 5 | "format": "uuid" 6 | } -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>Boshen/renovate"], 4 | "forkProcessing": "enabled" 5 | } 6 | -------------------------------------------------------------------------------- /schemars/tests/expected/no-variants.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "NoVariants", 4 | "type": "string", 5 | "enum": [] 6 | } -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-transparent-newtype.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "schema_fn", 4 | "type": "boolean" 5 | } -------------------------------------------------------------------------------- /schemars/tests/expected/struct-newtype.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Newtype", 4 | "type": "integer", 5 | "format": "int32" 6 | } -------------------------------------------------------------------------------- /schemars/tests/regex.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use regex::Regex; 3 | use util::*; 4 | 5 | #[test] 6 | fn regex() -> TestResult { 7 | test_default_generated_schema::("regex") 8 | } 9 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/regex.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use regex::Regex; 5 | 6 | forward_impl!(Regex => String); 7 | -------------------------------------------------------------------------------- /schemars/tests/ui/repr_non_unit_variant.stderr: -------------------------------------------------------------------------------- 1 | error: JsonSchema_repr: must be a unit variant 2 | --> $DIR/repr_non_unit_variant.rs:7:5 3 | | 4 | 7 | EmptyTuple(), 5 | | ^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /schemars/tests/expected/bigdecimal03.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Decimal", 4 | "type": "string", 5 | "pattern": "^-?[0-9]+(\\.[0-9]+)?$" 6 | } -------------------------------------------------------------------------------- /schemars/tests/expected/bigdecimal04.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Decimal", 4 | "type": "string", 5 | "pattern": "^-?[0-9]+(\\.[0-9]+)?$" 6 | } -------------------------------------------------------------------------------- /schemars/tests/expected/rust_decimal.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Decimal", 4 | "type": "string", 5 | "pattern": "^-?[0-9]+(\\.[0-9]+)?$" 6 | } -------------------------------------------------------------------------------- /schemars/tests/smol_str.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use smol_str::SmolStr; 3 | use util::*; 4 | 5 | #[test] 6 | fn smol_str() -> TestResult { 7 | test_default_generated_schema::("smol_str") 8 | } 9 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/smol_str.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use smol_str::SmolStr; 5 | 6 | forward_impl!(SmolStr => String); 7 | -------------------------------------------------------------------------------- /schemars/tests/bytes.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use bytes::{Bytes, BytesMut}; 3 | use util::*; 4 | 5 | #[test] 6 | fn bytes() -> TestResult { 7 | test_default_generated_schema::<(Bytes, BytesMut)>("bytes") 8 | } 9 | -------------------------------------------------------------------------------- /schemars/tests/expected/smallvec.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Array_of_String", 4 | "type": "array", 5 | "items": { 6 | "type": "string" 7 | } 8 | } -------------------------------------------------------------------------------- /schemars/tests/actual/README.md: -------------------------------------------------------------------------------- 1 | # Actual Generated Schemas 2 | 3 | If a test fails because a generated schema did not match the expected JSON, then the actual schema will be written to a JSON file in this directory. -------------------------------------------------------------------------------- /schemars/tests/either.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use either::Either; 3 | use util::*; 4 | 5 | #[test] 6 | fn either() -> TestResult { 7 | test_default_generated_schema::>>("either") 8 | } 9 | -------------------------------------------------------------------------------- /schemars/tests/smallvec.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use smallvec::SmallVec; 3 | use util::*; 4 | 5 | #[test] 6 | fn smallvec() -> TestResult { 7 | test_default_generated_schema::>("smallvec") 8 | } 9 | -------------------------------------------------------------------------------- /schemars/tests/ui/repr_non_unit_variant.rs: -------------------------------------------------------------------------------- 1 | use schemars::JsonSchema_repr; 2 | 3 | #[derive(JsonSchema_repr)] 4 | #[repr(u8)] 5 | pub enum Enum { 6 | Unit, 7 | EmptyTuple(), 8 | } 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /schemars/tests/expected/validate_newtype.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "NewType", 4 | "type": "integer", 5 | "format": "uint8", 6 | "maximum": 10.0, 7 | "minimum": 0.0 8 | } -------------------------------------------------------------------------------- /schemars/tests/expected/enum-repr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Enum", 4 | "type": "integer", 5 | "enum": [ 6 | 0, 7 | 1, 8 | 5, 9 | 6, 10 | 3 11 | ] 12 | } -------------------------------------------------------------------------------- /schemars/examples/enum_repr.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "SmallPrime", 4 | "type": "integer", 5 | "enum": [ 6 | 2, 7 | 3, 8 | 5, 9 | 7 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /docs/_includes/examples/enum_repr.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "SmallPrime", 4 | "type": "integer", 5 | "enum": [ 6 | 2, 7 | 3, 8 | 5, 9 | 7 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/smallvec.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use smallvec::{Array, SmallVec}; 5 | 6 | forward_impl!(( JsonSchema for SmallVec where A::Item: JsonSchema) => Vec); 7 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/bytes.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use bytes::{Bytes, BytesMut}; 5 | 6 | forward_impl!((JsonSchema for Bytes) => Vec); 7 | forward_impl!((JsonSchema for BytesMut) => Vec); 8 | -------------------------------------------------------------------------------- /schemars/tests/expected/arrayvec.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Array_up_to_size_16_of_int32", 4 | "type": "array", 5 | "items": { 6 | "type": "integer", 7 | "format": "int32" 8 | }, 9 | "maxItems": 16 10 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "schemars", 4 | "schemars_derive" 5 | ] 6 | resolver = "2" 7 | 8 | [workspace.dependencies] 9 | oxc-schemars = { version = "0.8.27", path = "schemars" } 10 | oxc_schemars_derive = { version = "0.8.26", path = "schemars_derive" } 11 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/enumset.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use enumset::{EnumSet, EnumSetType}; 5 | 6 | forward_impl!(( JsonSchema for EnumSet where T: EnumSetType + JsonSchema) => std::collections::BTreeSet); 7 | -------------------------------------------------------------------------------- /schemars/tests/uuid.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use util::*; 3 | 4 | #[test] 5 | fn uuid08() -> TestResult { 6 | test_default_generated_schema::("uuid") 7 | } 8 | 9 | #[test] 10 | fn uuid1() -> TestResult { 11 | test_default_generated_schema::("uuid") 12 | } 13 | -------------------------------------------------------------------------------- /schemars/tests/expected/enum-repr-with-attrs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Renamed", 4 | "description": "Description from comment", 5 | "type": "integer", 6 | "enum": [ 7 | 0, 8 | 1, 9 | 5, 10 | 6, 11 | 3 12 | ] 13 | } -------------------------------------------------------------------------------- /schemars/tests/expected/url.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "UrlTypes", 4 | "type": "object", 5 | "required": [ 6 | "url" 7 | ], 8 | "properties": { 9 | "url": { 10 | "type": "string", 11 | "format": "uri" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /schemars/tests/url.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use url::Url; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct UrlTypes { 9 | url: Url, 10 | } 11 | 12 | #[test] 13 | fn url_types() -> TestResult { 14 | test_default_generated_schema::("url") 15 | } 16 | -------------------------------------------------------------------------------- /schemars/tests/ui/repr_missing.stderr: -------------------------------------------------------------------------------- 1 | error: JsonSchema_repr: missing #[repr(...)] attribute 2 | --> $DIR/repr_missing.rs:3:10 3 | | 4 | 3 | #[derive(JsonSchema_repr)] 5 | | ^^^^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the derive macro `JsonSchema_repr` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /schemars/tests/enumset.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use enumset::{EnumSet, EnumSetType}; 3 | use schemars::JsonSchema; 4 | use util::*; 5 | 6 | #[derive(EnumSetType, JsonSchema)] 7 | enum Foo { 8 | Bar, 9 | Baz, 10 | } 11 | 12 | #[test] 13 | fn enumset() -> TestResult { 14 | test_default_generated_schema::>("enumset") 15 | } 16 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema-name-const-generics.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "const-generics-z-42", 4 | "type": "object", 5 | "required": [ 6 | "foo" 7 | ], 8 | "properties": { 9 | "foo": { 10 | "type": "integer", 11 | "format": "int32" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /schemars/tests/ui/invalid_attrs.rs: -------------------------------------------------------------------------------- 1 | use schemars::JsonSchema; 2 | 3 | #[derive(JsonSchema)] 4 | #[serde(default = 0, foo, deny_unknown_fields, deny_unknown_fields)] 5 | pub struct Struct1; 6 | 7 | #[derive(JsonSchema)] 8 | #[schemars(default = 0, foo, deny_unknown_fields, deny_unknown_fields)] 9 | pub struct Struct2; 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /schemars/tests/semver.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use semver::Version; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct SemverTypes { 9 | version: Version, 10 | } 11 | 12 | #[test] 13 | fn semver_types() -> TestResult { 14 | test_default_generated_schema::("semver") 15 | } 16 | -------------------------------------------------------------------------------- /schemars/tests/expected/skip_tuple_fields.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "TupleStruct", 4 | "type": "array", 5 | "items": [ 6 | { 7 | "type": "number", 8 | "format": "float" 9 | }, 10 | { 11 | "type": "null" 12 | } 13 | ], 14 | "maxItems": 2, 15 | "minItems": 2 16 | } -------------------------------------------------------------------------------- /update-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | cd schemars 5 | 6 | rm -f tests/actual/*.json 7 | 8 | TRYBUILD=overwrite cargo test --all-features --no-fail-fast --tests || : 9 | 10 | if ls tests/actual/*.json 1> /dev/null 2>&1; then 11 | mv -f tests/actual/*.json tests/expected/ 12 | else 13 | echo "Test schemas are up-to-date." 14 | fi 15 | -------------------------------------------------------------------------------- /schemars/examples/enum_repr.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema_repr}; 2 | 3 | #[derive(JsonSchema_repr)] 4 | #[repr(u8)] 5 | enum SmallPrime { 6 | Two = 2, 7 | Three = 3, 8 | Five = 5, 9 | Seven = 7, 10 | } 11 | 12 | fn main() { 13 | let schema = schema_for!(SmallPrime); 14 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 15 | } 16 | -------------------------------------------------------------------------------- /schemars/tests/expected/bound.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyContainer", 4 | "type": "object", 5 | "required": [ 6 | "associated", 7 | "generic" 8 | ], 9 | "properties": { 10 | "associated": { 11 | "type": "string" 12 | }, 13 | "generic": { 14 | "type": "null" 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /docs/_includes/example.md: -------------------------------------------------------------------------------- 1 | {% capture input %}examples/{{ include.name }}.rs{% endcapture %} 2 | {% capture output %}examples/{{ include.name }}.schema.json{% endcapture %} 3 | 4 | ```rust 5 | {% include {{ input }} %} 6 | ``` 7 | 8 |
9 | Click to see the output JSON schema... 10 | 11 | ```json 12 | {% include {{ output }} -%} 13 | ``` 14 |
15 | -------------------------------------------------------------------------------- /docs/_includes/examples/enum_repr.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema_repr}; 2 | 3 | #[derive(JsonSchema_repr)] 4 | #[repr(u8)] 5 | enum SmallPrime { 6 | Two = 2, 7 | Three = 3, 8 | Five = 5, 9 | Seven = 7, 10 | } 11 | 12 | fn main() { 13 | let schema = schema_for!(SmallPrime); 14 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 15 | } 16 | -------------------------------------------------------------------------------- /schemars/tests/ffi.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use std::ffi::{OsStr, OsString}; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct OsStrings { 9 | owned: OsString, 10 | borrowed: &'static OsStr, 11 | } 12 | 13 | #[test] 14 | fn os_strings() -> TestResult { 15 | test_default_generated_schema::("os_strings") 16 | } 17 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/indexmap.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use indexmap::{IndexMap, IndexSet}; 5 | use std::collections::{HashMap, HashSet}; 6 | 7 | forward_impl!(( JsonSchema for IndexMap) => HashMap); 8 | forward_impl!(( JsonSchema for IndexSet) => HashSet); 9 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/indexmap2.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use indexmap2::{IndexMap, IndexSet}; 5 | use std::collections::{HashMap, HashSet}; 6 | 7 | forward_impl!(( JsonSchema for IndexMap) => HashMap); 8 | forward_impl!(( JsonSchema for IndexSet) => HashSet); 9 | -------------------------------------------------------------------------------- /schemars/tests/expected/enumset.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Set_of_Foo", 4 | "type": "array", 5 | "items": { 6 | "$ref": "#/definitions/Foo" 7 | }, 8 | "uniqueItems": true, 9 | "definitions": { 10 | "Foo": { 11 | "type": "string", 12 | "enum": [ 13 | "Bar", 14 | "Baz" 15 | ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-tuple.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Tuple", 4 | "type": "array", 5 | "items": [ 6 | { 7 | "type": "boolean" 8 | }, 9 | { 10 | "type": "integer", 11 | "format": "int32" 12 | }, 13 | { 14 | "type": "boolean" 15 | } 16 | ], 17 | "maxItems": 3, 18 | "minItems": 3 19 | } -------------------------------------------------------------------------------- /schemars/tests/expected/validate_tuple.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Tuple", 4 | "type": "array", 5 | "items": [ 6 | { 7 | "type": "integer", 8 | "format": "uint8", 9 | "maximum": 10.0, 10 | "minimum": 0.0 11 | }, 12 | { 13 | "type": "boolean" 14 | } 15 | ], 16 | "maxItems": 2, 17 | "minItems": 2 18 | } -------------------------------------------------------------------------------- /schemars/tests/ui/schema_for_arg_value.stderr: -------------------------------------------------------------------------------- 1 | error: This argument to `schema_for!` is not a type - did you mean to use `schema_for_value!` instead? 2 | --> $DIR/schema_for_arg_value.rs:4:19 3 | | 4 | 4 | let _schema = schema_for!(123); 5 | | ^^^^^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the macro `schema_for` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /schemars/tests/indexmap.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use indexmap::{IndexMap, IndexSet}; 3 | use schemars::JsonSchema; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct IndexMapTypes { 9 | map: IndexMap, 10 | set: IndexSet, 11 | } 12 | 13 | #[test] 14 | fn indexmap_types() -> TestResult { 15 | test_default_generated_schema::("indexmap") 16 | } 17 | -------------------------------------------------------------------------------- /schemars/tests/indexmap2.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use indexmap2::{IndexMap, IndexSet}; 3 | use schemars::JsonSchema; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct IndexMapTypes { 9 | map: IndexMap, 10 | set: IndexSet, 11 | } 12 | 13 | #[test] 14 | fn indexmap_types() -> TestResult { 15 | test_default_generated_schema::("indexmap") 16 | } 17 | -------------------------------------------------------------------------------- /docs/_sass/color_schemes/default.scss: -------------------------------------------------------------------------------- 1 | // Overridable variables at https://github.com/pmarsceill/just-the-docs/blob/master/_sass/support/_variables.scss 2 | 3 | $body-text-color: $grey-dk-200; 4 | 5 | $nav-child-link-color: $link-color; 6 | 7 | $content-width: 900px; 8 | 9 | $media-queries: ( 10 | xs: 320px, 11 | sm: 500px, 12 | md: $content-width, 13 | lg: $content-width + $nav-width, 14 | xl: 1400px 15 | ); -------------------------------------------------------------------------------- /schemars/tests/time.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use std::time::{Duration, SystemTime}; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct MyStruct { 9 | duration: Duration, 10 | time: SystemTime, 11 | } 12 | 13 | #[test] 14 | fn duration_and_systemtime() -> TestResult { 15 | test_default_generated_schema::("duration_and_systemtime") 16 | } 17 | -------------------------------------------------------------------------------- /update-examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | cd schemars/examples 5 | 6 | rm -f *.schema.json 7 | 8 | for file in *.rs 9 | do 10 | example=${file%.rs} 11 | cargo run --example "$example" > "$example.schema.json" 12 | done 13 | 14 | cd ../.. 15 | 16 | rm -f docs/_includes/examples/*.rs 17 | rm -f docs/_includes/examples/*.schema.json 18 | 19 | cp schemars/examples/* docs/_includes/examples/ 20 | -------------------------------------------------------------------------------- /docs/examples/1-derive_jsonschema.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Deriving JsonSchema 4 | parent: Examples 5 | nav_order: 1 6 | summary: Deriving JsonSchema on a struct and enum. 7 | --- 8 | 9 | # Deriving JsonSchema 10 | 11 | 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. 12 | 13 | {% include example.md name="main" %} 14 | -------------------------------------------------------------------------------- /schemars/tests/range.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use std::ops::{Bound, Range, RangeInclusive}; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct MyStruct { 9 | range: Range, 10 | inclusive: RangeInclusive, 11 | bound: Bound, 12 | } 13 | 14 | #[test] 15 | fn result() -> TestResult { 16 | test_default_generated_schema::("range") 17 | } 18 | -------------------------------------------------------------------------------- /schemars/tests/expected/crate_alias.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Struct", 4 | "type": "object", 5 | "required": [ 6 | "bar", 7 | "foo" 8 | ], 9 | "properties": { 10 | "foo": { 11 | "description": "This is a document", 12 | "type": "integer", 13 | "format": "int32" 14 | }, 15 | "bar": { 16 | "type": "boolean" 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /schemars/tests/expected/either.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Either_int32_or_Either_Boolean_or_Null", 4 | "anyOf": [ 5 | { 6 | "type": "integer", 7 | "format": "int32" 8 | }, 9 | { 10 | "anyOf": [ 11 | { 12 | "type": "boolean" 13 | }, 14 | { 15 | "type": "null" 16 | } 17 | ] 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /schemars/tests/expected/macro_built_struct.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "A", 4 | "type": "object", 5 | "required": [ 6 | "v", 7 | "x" 8 | ], 9 | "properties": { 10 | "x": { 11 | "type": "integer", 12 | "format": "uint8", 13 | "minimum": 0.0 14 | }, 15 | "v": { 16 | "type": "integer", 17 | "format": "int32" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /schemars/tests/nonzero_ints.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | struct MyStruct { 8 | unsigned: u32, 9 | nonzero_unsigned: std::num::NonZeroU32, 10 | signed: i32, 11 | nonzero_signed: std::num::NonZeroI32, 12 | } 13 | 14 | #[test] 15 | fn nonzero_ints() -> TestResult { 16 | test_default_generated_schema::("nonzero_ints") 17 | } 18 | -------------------------------------------------------------------------------- /schemars/tests/expected/struct-tuple.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Tuple", 4 | "type": "array", 5 | "items": [ 6 | { 7 | "type": "integer", 8 | "format": "int32" 9 | }, 10 | { 11 | "type": "boolean" 12 | }, 13 | { 14 | "type": [ 15 | "string", 16 | "null" 17 | ] 18 | } 19 | ], 20 | "maxItems": 3, 21 | "minItems": 3 22 | } -------------------------------------------------------------------------------- /schemars/tests/struct_additional_properties.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | #[serde(deny_unknown_fields)] 8 | pub struct Struct { 9 | foo: i32, 10 | bar: bool, 11 | baz: Option, 12 | } 13 | 14 | #[test] 15 | fn struct_normal_additional_properties() -> TestResult { 16 | test_default_generated_schema::("struct-normal-additional-properties") 17 | } 18 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-struct.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Struct", 4 | "type": "object", 5 | "required": [ 6 | "bar", 7 | "baz", 8 | "foo" 9 | ], 10 | "properties": { 11 | "foo": { 12 | "type": "boolean" 13 | }, 14 | "bar": { 15 | "type": "integer", 16 | "format": "int32" 17 | }, 18 | "baz": { 19 | "type": "boolean" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /schemars/tests/result.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | struct MyStruct { 8 | foo: i32, 9 | } 10 | 11 | #[allow(dead_code)] 12 | #[derive(JsonSchema)] 13 | struct Container { 14 | result1: Result>, 15 | result2: Result, 16 | } 17 | 18 | #[test] 19 | fn result() -> TestResult { 20 | test_default_generated_schema::("result") 21 | } 22 | -------------------------------------------------------------------------------- /schemars/tests/decimal.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use util::*; 3 | 4 | #[test] 5 | fn rust_decimal() -> TestResult { 6 | test_default_generated_schema::("rust_decimal") 7 | } 8 | 9 | #[test] 10 | fn bigdecimal03() -> TestResult { 11 | test_default_generated_schema::("bigdecimal03") 12 | } 13 | 14 | #[test] 15 | fn bigdecimal04() -> TestResult { 16 | test_default_generated_schema::("bigdecimal04") 17 | } 18 | -------------------------------------------------------------------------------- /schemars/tests/expected/deprecated-struct.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "DeprecatedStruct", 4 | "deprecated": true, 5 | "type": "object", 6 | "required": [ 7 | "deprecated_field", 8 | "foo" 9 | ], 10 | "properties": { 11 | "foo": { 12 | "type": "integer", 13 | "format": "int32" 14 | }, 15 | "deprecated_field": { 16 | "deprecated": true, 17 | "type": "boolean" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /schemars/tests/crate_alias.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use ::schemars as not_schemars; 3 | use util::*; 4 | 5 | #[allow(unused_imports)] 6 | use std as schemars; 7 | 8 | #[allow(dead_code)] 9 | #[derive(not_schemars::JsonSchema)] 10 | #[schemars(crate = "not_schemars")] 11 | struct Struct { 12 | /// This is a document 13 | foo: i32, 14 | bar: bool, 15 | } 16 | 17 | #[test] 18 | fn test_crate_alias() -> TestResult { 19 | test_default_generated_schema::("crate_alias") 20 | } 21 | -------------------------------------------------------------------------------- /schemars/tests/chrono.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use chrono::prelude::*; 3 | use schemars::JsonSchema; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct ChronoTypes { 9 | weekday: Weekday, 10 | date_time: DateTime, 11 | naive_date: NaiveDate, 12 | naive_date_time: NaiveDateTime, 13 | naive_time: NaiveTime, 14 | } 15 | 16 | #[test] 17 | fn chrono_types() -> TestResult { 18 | test_default_generated_schema::("chrono-types") 19 | } 20 | -------------------------------------------------------------------------------- /schemars/tests/expected/semver.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "SemverTypes", 4 | "type": "object", 5 | "required": ["version"], 6 | "properties": { 7 | "version": { 8 | "type": "string", 9 | "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /schemars/tests/expected/struct-normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Struct", 4 | "type": "object", 5 | "required": [ 6 | "bar", 7 | "foo" 8 | ], 9 | "properties": { 10 | "foo": { 11 | "type": "integer", 12 | "format": "int32" 13 | }, 14 | "bar": { 15 | "type": "boolean" 16 | }, 17 | "baz": { 18 | "type": [ 19 | "string", 20 | "null" 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | permissions: {} 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | release-plz: 12 | name: Release-plz 13 | runs-on: ubuntu-latest 14 | permissions: 15 | pull-requests: write 16 | contents: write 17 | id-token: write 18 | steps: 19 | - uses: oxc-project/release-plz@44b98e8dda1a7783d4ec2ef66e2f37a3e8c1c759 # v1.0.4 20 | with: 21 | PAT: ${{ secrets.OXC_BOT_PAT }} 22 | -------------------------------------------------------------------------------- /schemars/examples/main.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | 3 | #[derive(JsonSchema)] 4 | pub struct MyStruct { 5 | pub my_int: i32, 6 | pub my_bool: bool, 7 | pub my_nullable_enum: Option, 8 | } 9 | 10 | #[derive(JsonSchema)] 11 | pub enum MyEnum { 12 | StringNewType(String), 13 | StructVariant { floats: Vec }, 14 | } 15 | 16 | fn main() { 17 | let schema = schema_for!(MyStruct); 18 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 19 | } 20 | -------------------------------------------------------------------------------- /docs/_includes/examples/main.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | 3 | #[derive(JsonSchema)] 4 | pub struct MyStruct { 5 | pub my_int: i32, 6 | pub my_bool: bool, 7 | pub my_nullable_enum: Option, 8 | } 9 | 10 | #[derive(JsonSchema)] 11 | pub enum MyEnum { 12 | StringNewType(String), 13 | StructVariant { floats: Vec }, 14 | } 15 | 16 | fn main() { 17 | let schema = schema_for!(MyStruct); 18 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 19 | } 20 | -------------------------------------------------------------------------------- /schemars/tests/expected/inline-subschemas.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyJob", 4 | "type": "object", 5 | "required": [ 6 | "spec" 7 | ], 8 | "properties": { 9 | "spec": { 10 | "type": "object", 11 | "required": [ 12 | "replicas" 13 | ], 14 | "properties": { 15 | "replicas": { 16 | "type": "integer", 17 | "format": "uint32", 18 | "minimum": 0.0 19 | } 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /schemars/examples/from_value.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "examples": [ 5 | { 6 | "my_bool": true, 7 | "my_int": 123, 8 | "my_nullable_enum": { 9 | "StringNewType": "foo" 10 | } 11 | } 12 | ], 13 | "type": "object", 14 | "properties": { 15 | "my_bool": { 16 | "type": "boolean" 17 | }, 18 | "my_int": { 19 | "type": "integer" 20 | }, 21 | "my_nullable_enum": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/_includes/examples/from_value.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "examples": [ 5 | { 6 | "my_bool": true, 7 | "my_int": 123, 8 | "my_nullable_enum": { 9 | "StringNewType": "foo" 10 | } 11 | } 12 | ], 13 | "type": "object", 14 | "properties": { 15 | "my_bool": { 16 | "type": "boolean" 17 | }, 18 | "my_int": { 19 | "type": "integer" 20 | }, 21 | "my_nullable_enum": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /schemars/tests/expected/struct-normal-additional-properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Struct", 4 | "type": "object", 5 | "required": [ 6 | "bar", 7 | "foo" 8 | ], 9 | "properties": { 10 | "foo": { 11 | "type": "integer", 12 | "format": "int32" 13 | }, 14 | "bar": { 15 | "type": "boolean" 16 | }, 17 | "baz": { 18 | "type": [ 19 | "string", 20 | "null" 21 | ] 22 | } 23 | }, 24 | "additionalProperties": false 25 | } -------------------------------------------------------------------------------- /docs/examples/4-custom_settings.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Custom Schema Settings 4 | parent: Examples 5 | nav_order: 4 6 | summary: Generating a schema using custom settings which changes how Option is handled. 7 | --- 8 | 9 | # Custom Schema Settings 10 | 11 | The `gen` module allows you to customise how schemas are generated. For example, the default behaviour for `Option` is to include `null` in the schema's `type`s, but we can instead add a `nullable` property to its schema: 12 | 13 | {% include example.md name="custom_settings" %} 14 | -------------------------------------------------------------------------------- /schemars/tests/expected/skip_struct_fields.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "included", 7 | "writable" 8 | ], 9 | "properties": { 10 | "readable": { 11 | "default": "", 12 | "readOnly": true, 13 | "type": "string" 14 | }, 15 | "writable": { 16 | "writeOnly": true, 17 | "type": "number", 18 | "format": "float" 19 | }, 20 | "included": { 21 | "type": "null" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /schemars/tests/property_name.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | #[serde(rename_all = "camelCase")] 8 | struct MyStruct { 9 | camel_case: i32, 10 | #[serde(rename = "new_name_1")] 11 | old_name_1: i32, 12 | #[serde(rename = "ignored")] 13 | #[schemars(rename = "new_name_2")] 14 | old_name_2: i32, 15 | } 16 | 17 | #[test] 18 | fn set_struct_property_names() -> TestResult { 19 | test_default_generated_schema::("property-name-struct") 20 | } 21 | -------------------------------------------------------------------------------- /schemars/tests/expected/doc_comments_override.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "OverrideDocs struct", 4 | "description": "New description", 5 | "type": "object", 6 | "required": [ 7 | "my_int", 8 | "my_undocumented_bool" 9 | ], 10 | "properties": { 11 | "my_int": { 12 | "title": "My integer", 13 | "description": "This is an i32", 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "my_undocumented_bool": { 18 | "type": "boolean" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /schemars/tests/expected/indexmap.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "IndexMapTypes", 4 | "type": "object", 5 | "required": [ 6 | "map", 7 | "set" 8 | ], 9 | "properties": { 10 | "map": { 11 | "type": "object", 12 | "additionalProperties": { 13 | "type": "boolean" 14 | } 15 | }, 16 | "set": { 17 | "type": "array", 18 | "items": { 19 | "type": "integer", 20 | "format": "int" 21 | }, 22 | "uniqueItems": true 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /schemars/tests/expected/property-name-struct.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "camelCase", 7 | "new_name_1", 8 | "new_name_2" 9 | ], 10 | "properties": { 11 | "camelCase": { 12 | "type": "integer", 13 | "format": "int32" 14 | }, 15 | "new_name_1": { 16 | "type": "integer", 17 | "format": "int32" 18 | }, 19 | "new_name_2": { 20 | "type": "integer", 21 | "format": "int32" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /schemars/tests/expected/skip_enum_variants.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyEnum", 4 | "oneOf": [ 5 | { 6 | "type": "string", 7 | "enum": [ 8 | "Included2" 9 | ] 10 | }, 11 | { 12 | "type": "object", 13 | "required": [ 14 | "Included1" 15 | ], 16 | "properties": { 17 | "Included1": { 18 | "type": "number", 19 | "format": "float" 20 | } 21 | }, 22 | "additionalProperties": false 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404 3 | layout: default 4 | nav_exclude: true 5 | title: Not Found 6 | --- 7 | 8 | 22 | 23 |
24 |

404

25 | 26 |

Page not found :(

27 |

The requested page could not be found.

28 |
-------------------------------------------------------------------------------- /schemars/tests/expected/bytes.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Tuple_of_Array_of_uint8_and_Array_of_uint8", 4 | "type": "array", 5 | "items": [ 6 | { 7 | "type": "array", 8 | "items": { 9 | "type": "integer", 10 | "format": "uint8", 11 | "minimum": 0.0 12 | } 13 | }, 14 | { 15 | "type": "array", 16 | "items": { 17 | "type": "integer", 18 | "format": "uint8", 19 | "minimum": 0.0 20 | } 21 | } 22 | ], 23 | "maxItems": 2, 24 | "minItems": 2 25 | } -------------------------------------------------------------------------------- /docs/assets/js/search-data.json: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | { 4 | {% for page in site.html_pages %}{% if page.search_exclude != true %}"{{ forloop.index0 }}": { 5 | "id": "{{ forloop.index0 }}", 6 | "title": "{{ page.title | replace: '&', '&' }}", 7 | "content": "{{ page.content | markdownify | strip_html | escape_once | remove: 'Table of contents' | remove: '```' | remove: '---' | replace: '\', ' ' | normalize_whitespace }}", 8 | "url": "{{ page.url | absolute_url }}", 9 | "relUrl": "{{ page.url }}" 10 | }{% unless forloop.last %},{% endunless %} 11 | {% endif %}{% endfor %} 12 | } 13 | -------------------------------------------------------------------------------- /docs/examples/3-schemars_attrs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Using Schemars Attributes 4 | parent: Examples 5 | nav_order: 3 6 | summary: 'Deriving JsonSchema on types that use #[schemars] attributes to customise serialization behaviour.' 7 | --- 8 | 9 | # Using Serde Attributes 10 | 11 | `#[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. 12 | 13 | {% include example.md name="schemars_attrs" %} 14 | -------------------------------------------------------------------------------- /schemars/tests/examples.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use serde::Serialize; 4 | use util::*; 5 | 6 | #[derive(Default, JsonSchema, Serialize)] 7 | #[schemars(example = "Struct::default", example = "null")] 8 | struct Struct { 9 | #[schemars(example = "eight", example = "null")] 10 | foo: i32, 11 | bar: bool, 12 | #[schemars(example = "null")] 13 | baz: Option<&'static str>, 14 | } 15 | 16 | fn eight() -> i32 { 17 | 8 18 | } 19 | 20 | fn null() {} 21 | 22 | #[test] 23 | fn examples() -> TestResult { 24 | test_default_generated_schema::("examples") 25 | } 26 | -------------------------------------------------------------------------------- /schemars/tests/schema_for_schema.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::r#gen::SchemaSettings; 3 | use schemars::schema::RootSchema; 4 | use util::*; 5 | 6 | #[test] 7 | fn schema_matches_draft07() -> TestResult { 8 | test_generated_schema::("schema", SchemaSettings::draft07()) 9 | } 10 | 11 | #[test] 12 | fn schema_matches_2019_09() -> TestResult { 13 | test_generated_schema::("schema-2019_09", SchemaSettings::draft2019_09()) 14 | } 15 | 16 | #[test] 17 | fn schema_matches_openapi3() -> TestResult { 18 | test_generated_schema::("schema-openapi3", SchemaSettings::openapi3()) 19 | } 20 | -------------------------------------------------------------------------------- /schemars/examples/custom_serialization.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "properties": { 6 | "bool_as_string": { 7 | "default": "false", 8 | "type": "string", 9 | "format": "boolean" 10 | }, 11 | "bool_normal": { 12 | "default": false, 13 | "type": "boolean" 14 | }, 15 | "int_as_string": { 16 | "default": "8", 17 | "type": "string" 18 | }, 19 | "int_normal": { 20 | "default": 8, 21 | "type": "integer", 22 | "format": "int32" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /schemars/tests/expected/enum-unit-doc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "SoundOfMusic", 4 | "oneOf": [ 5 | { 6 | "title": "A deer", 7 | "description": "A female deer", 8 | "type": "string", 9 | "enum": [ 10 | "Do" 11 | ] 12 | }, 13 | { 14 | "description": "A drop of golden sun", 15 | "type": "string", 16 | "enum": [ 17 | "Re" 18 | ] 19 | }, 20 | { 21 | "description": "A name I call myself", 22 | "type": "string", 23 | "enum": [ 24 | "Mi" 25 | ] 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /docs/_includes/examples/custom_serialization.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "properties": { 6 | "bool_as_string": { 7 | "default": "false", 8 | "type": "string", 9 | "format": "boolean" 10 | }, 11 | "bool_normal": { 12 | "default": false, 13 | "type": "boolean" 14 | }, 15 | "int_as_string": { 16 | "default": "8", 17 | "type": "string" 18 | }, 19 | "int_normal": { 20 | "default": 8, 21 | "type": "integer", 22 | "format": "int32" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /schemars/tests/arrayvec.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use util::*; 3 | 4 | #[test] 5 | fn arrayvec05() -> TestResult { 6 | test_default_generated_schema::>("arrayvec") 7 | } 8 | 9 | #[test] 10 | fn arrayvec05_string() -> TestResult { 11 | test_default_generated_schema::>("arrayvec_string") 12 | } 13 | 14 | #[test] 15 | fn arrayvec07() -> TestResult { 16 | test_default_generated_schema::>("arrayvec") 17 | } 18 | 19 | #[test] 20 | fn arrayvec07_string() -> TestResult { 21 | test_default_generated_schema::>("arrayvec_string") 22 | } 23 | -------------------------------------------------------------------------------- /schemars/examples/from_value.rs: -------------------------------------------------------------------------------- 1 | use schemars::schema_for_value; 2 | use serde::Serialize; 3 | 4 | #[derive(Serialize)] 5 | pub struct MyStruct { 6 | pub my_int: i32, 7 | pub my_bool: bool, 8 | pub my_nullable_enum: Option, 9 | } 10 | 11 | #[derive(Serialize)] 12 | pub enum MyEnum { 13 | StringNewType(String), 14 | StructVariant { floats: Vec }, 15 | } 16 | 17 | fn main() { 18 | let schema = schema_for_value!(MyStruct { 19 | my_int: 123, 20 | my_bool: true, 21 | my_nullable_enum: Some(MyEnum::StringNewType("foo".to_string())) 22 | }); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /docs/_includes/examples/from_value.rs: -------------------------------------------------------------------------------- 1 | use schemars::schema_for_value; 2 | use serde::Serialize; 3 | 4 | #[derive(Serialize)] 5 | pub struct MyStruct { 6 | pub my_int: i32, 7 | pub my_bool: bool, 8 | pub my_nullable_enum: Option, 9 | } 10 | 11 | #[derive(Serialize)] 12 | pub enum MyEnum { 13 | StringNewType(String), 14 | StructVariant { floats: Vec }, 15 | } 16 | 17 | fn main() { 18 | let schema = schema_for_value!(MyStruct { 19 | my_int: 123, 20 | my_bool: true, 21 | my_nullable_enum: Some(MyEnum::StringNewType("foo".to_string())) 22 | }); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /schemars/examples/validate.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | 3 | #[derive(JsonSchema)] 4 | pub struct MyStruct { 5 | #[validate(range(min = 1, max = 10))] 6 | pub my_int: i32, 7 | pub my_bool: bool, 8 | #[validate(required)] 9 | pub my_nullable_enum: Option, 10 | } 11 | 12 | #[derive(JsonSchema)] 13 | pub enum MyEnum { 14 | StringNewType(#[validate(phone)] String), 15 | StructVariant { 16 | #[validate(length(min = 1, max = 100))] 17 | floats: Vec, 18 | }, 19 | } 20 | 21 | fn main() { 22 | let schema = schema_for!(MyStruct); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /schemars/tests/expected/flatten.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Flat", 4 | "type": "object", 5 | "required": [ 6 | "b", 7 | "f", 8 | "s", 9 | "v" 10 | ], 11 | "properties": { 12 | "f": { 13 | "type": "number", 14 | "format": "float" 15 | }, 16 | "b": { 17 | "type": "boolean" 18 | }, 19 | "s": { 20 | "type": "string" 21 | }, 22 | "os": { 23 | "default": "", 24 | "type": "string" 25 | }, 26 | "v": { 27 | "type": "array", 28 | "items": { 29 | "type": "integer", 30 | "format": "int32" 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /docs/_includes/examples/validate.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | 3 | #[derive(JsonSchema)] 4 | pub struct MyStruct { 5 | #[validate(range(min = 1, max = 10))] 6 | pub my_int: i32, 7 | pub my_bool: bool, 8 | #[validate(required)] 9 | pub my_nullable_enum: Option, 10 | } 11 | 12 | #[derive(JsonSchema)] 13 | pub enum MyEnum { 14 | StringNewType(#[validate(phone)] String), 15 | StructVariant { 16 | #[validate(length(min = 1, max = 100))] 17 | floats: Vec, 18 | }, 19 | } 20 | 21 | fn main() { 22 | let schema = schema_for!(MyStruct); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /schemars/tests/same_name.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | mod a { 6 | use super::*; 7 | 8 | #[allow(dead_code)] 9 | #[derive(JsonSchema)] 10 | pub struct Config { 11 | test: String, 12 | } 13 | } 14 | 15 | mod b { 16 | use super::*; 17 | 18 | #[allow(dead_code)] 19 | #[derive(JsonSchema)] 20 | pub struct Config { 21 | test2: String, 22 | } 23 | } 24 | 25 | #[allow(dead_code)] 26 | #[derive(JsonSchema)] 27 | pub struct Config2 { 28 | a_cfg: a::Config, 29 | b_cfg: b::Config, 30 | } 31 | 32 | #[test] 33 | fn same_name() -> TestResult { 34 | test_default_generated_schema::("same_name") 35 | } 36 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/url.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | use url::Url; 6 | 7 | impl JsonSchema for Url { 8 | no_ref_schema!(); 9 | 10 | fn schema_name() -> String { 11 | "Url".to_owned() 12 | } 13 | 14 | fn schema_id() -> Cow<'static, str> { 15 | Cow::Borrowed("url::Url") 16 | } 17 | 18 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 19 | SchemaObject { 20 | instance_type: Some(InstanceType::String.into()), 21 | format: Some("uri".to_owned()), 22 | ..Default::default() 23 | } 24 | .into() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /schemars_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "oxc_schemars_derive" 3 | description = "Macros for #[derive(JsonSchema)], for use with schemars" 4 | repository = "https://github.com/oxc-project/schemars" 5 | version = "0.8.26" 6 | authors = ["Graham Esau "] 7 | edition = "2021" 8 | license = "MIT" 9 | readme = "README.md" 10 | keywords = ["rust", "json-schema", "serde"] 11 | rust-version = "1.60" 12 | 13 | [lib] 14 | name = "schemars_derive" 15 | proc-macro = true 16 | 17 | [dependencies] 18 | proc-macro2 = "1.0" 19 | quote = "1.0" 20 | syn = { version = "2.0", features = ["extra-traits"] } 21 | serde_derive_internals = "0.29" 22 | 23 | [dev-dependencies] 24 | pretty_assertions = "1.2.1" 25 | -------------------------------------------------------------------------------- /docs/examples/8-enum_repr.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Serialize Enum as Number (serde_repr) 4 | parent: Examples 5 | nav_order: 8 6 | summary: >- 7 | Generating a schema for with a C-like enum compatible with serde_repr. 8 | --- 9 | 10 | # Serialize Enum as Number (serde_repr Compatibility) 11 | 12 | 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. 13 | 14 | {% include example.md name="enum_repr" %} 15 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/uuid08.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | use uuid08::Uuid; 6 | 7 | impl JsonSchema for Uuid { 8 | no_ref_schema!(); 9 | 10 | fn schema_name() -> String { 11 | "Uuid".to_string() 12 | } 13 | 14 | fn schema_id() -> Cow<'static, str> { 15 | Cow::Borrowed("uuid::Uuid") 16 | } 17 | 18 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 19 | SchemaObject { 20 | instance_type: Some(InstanceType::String.into()), 21 | format: Some("uuid".to_string()), 22 | ..Default::default() 23 | } 24 | .into() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/uuid1.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | use uuid1::Uuid; 6 | 7 | impl JsonSchema for Uuid { 8 | no_ref_schema!(); 9 | 10 | fn schema_name() -> String { 11 | "Uuid".to_string() 12 | } 13 | 14 | fn schema_id() -> Cow<'static, str> { 15 | Cow::Borrowed("uuid::Uuid") 16 | } 17 | 18 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 19 | SchemaObject { 20 | instance_type: Some(InstanceType::String.into()), 21 | format: Some("uuid".to_string()), 22 | ..Default::default() 23 | } 24 | .into() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /schemars/tests/expected/transparent-struct.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "OuterStruct", 4 | "type": "object", 5 | "properties": { 6 | "inner": { 7 | "anyOf": [ 8 | { 9 | "$ref": "#/definitions/InnerStruct" 10 | }, 11 | { 12 | "type": "null" 13 | } 14 | ] 15 | } 16 | }, 17 | "definitions": { 18 | "InnerStruct": { 19 | "type": "array", 20 | "items": [ 21 | { 22 | "type": "string" 23 | }, 24 | { 25 | "type": "integer", 26 | "format": "int32" 27 | } 28 | ], 29 | "maxItems": 2, 30 | "minItems": 2 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /schemars/tests/expected/macro_built_enum.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "OuterEnum", 4 | "oneOf": [ 5 | { 6 | "type": "object", 7 | "required": [ 8 | "InnerStruct" 9 | ], 10 | "properties": { 11 | "InnerStruct": { 12 | "$ref": "#/definitions/InnerStruct" 13 | } 14 | }, 15 | "additionalProperties": false 16 | } 17 | ], 18 | "definitions": { 19 | "InnerStruct": { 20 | "type": "object", 21 | "required": [ 22 | "x" 23 | ], 24 | "properties": { 25 | "x": { 26 | "type": "integer", 27 | "format": "int32" 28 | } 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /schemars/tests/expected/examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Struct", 4 | "examples": [ 5 | { 6 | "bar": false, 7 | "baz": null, 8 | "foo": 0 9 | }, 10 | null 11 | ], 12 | "type": "object", 13 | "required": [ 14 | "bar", 15 | "foo" 16 | ], 17 | "properties": { 18 | "foo": { 19 | "examples": [ 20 | 8, 21 | null 22 | ], 23 | "type": "integer", 24 | "format": "int32" 25 | }, 26 | "bar": { 27 | "type": "boolean" 28 | }, 29 | "baz": { 30 | "examples": [ 31 | null 32 | ], 33 | "type": [ 34 | "string", 35 | "null" 36 | ] 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /schemars/examples/serde_attrs.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Deserialize, Serialize, JsonSchema)] 5 | #[serde(rename_all = "camelCase", deny_unknown_fields)] 6 | pub struct MyStruct { 7 | #[serde(rename = "myNumber")] 8 | pub my_int: i32, 9 | pub my_bool: bool, 10 | #[serde(default)] 11 | pub my_nullable_enum: Option, 12 | } 13 | 14 | #[derive(Deserialize, Serialize, JsonSchema)] 15 | #[serde(untagged)] 16 | pub enum MyEnum { 17 | StringNewType(String), 18 | StructVariant { floats: Vec }, 19 | } 20 | 21 | fn main() { 22 | let schema = schema_for!(MyStruct); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /docs/_includes/examples/serde_attrs.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Deserialize, Serialize, JsonSchema)] 5 | #[serde(rename_all = "camelCase", deny_unknown_fields)] 6 | pub struct MyStruct { 7 | #[serde(rename = "myNumber")] 8 | pub my_int: i32, 9 | pub my_bool: bool, 10 | #[serde(default)] 11 | pub my_nullable_enum: Option, 12 | } 13 | 14 | #[derive(Deserialize, Serialize, JsonSchema)] 15 | #[serde(untagged)] 16 | pub enum MyEnum { 17 | StringNewType(String), 18 | StructVariant { floats: Vec }, 19 | } 20 | 21 | fn main() { 22 | let schema = schema_for!(MyStruct); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /schemars/examples/custom_settings.rs: -------------------------------------------------------------------------------- 1 | use schemars::{r#gen::SchemaSettings, JsonSchema}; 2 | 3 | #[derive(JsonSchema)] 4 | pub struct MyStruct { 5 | pub my_int: i32, 6 | pub my_bool: bool, 7 | pub my_nullable_enum: Option, 8 | } 9 | 10 | #[derive(JsonSchema)] 11 | pub enum MyEnum { 12 | StringNewType(String), 13 | StructVariant { floats: Vec }, 14 | } 15 | 16 | fn main() { 17 | let settings = SchemaSettings::draft07().with(|s| { 18 | s.option_nullable = true; 19 | s.option_add_null_type = false; 20 | }); 21 | let generator = settings.into_generator(); 22 | let schema = generator.into_root_schema_for::(); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /schemars/tests/enum_repr.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema_repr; 3 | use util::*; 4 | 5 | #[derive(JsonSchema_repr)] 6 | #[repr(u8)] 7 | pub enum Enum { 8 | Zero, 9 | One, 10 | Five = 5, 11 | Six, 12 | Three = 3, 13 | } 14 | 15 | #[test] 16 | fn enum_repr() -> TestResult { 17 | test_default_generated_schema::("enum-repr") 18 | } 19 | 20 | #[derive(JsonSchema_repr)] 21 | #[repr(i64)] 22 | #[serde(rename = "Renamed")] 23 | /// Description from comment 24 | pub enum EnumWithAttrs { 25 | Zero, 26 | One, 27 | Five = 5, 28 | Six, 29 | Three = 3, 30 | } 31 | 32 | #[test] 33 | fn enum_repr_with_attrs() -> TestResult { 34 | test_default_generated_schema::("enum-repr-with-attrs") 35 | } 36 | -------------------------------------------------------------------------------- /docs/_includes/examples/custom_settings.rs: -------------------------------------------------------------------------------- 1 | use schemars::{r#gen::SchemaSettings, JsonSchema}; 2 | 3 | #[derive(JsonSchema)] 4 | pub struct MyStruct { 5 | pub my_int: i32, 6 | pub my_bool: bool, 7 | pub my_nullable_enum: Option, 8 | } 9 | 10 | #[derive(JsonSchema)] 11 | pub enum MyEnum { 12 | StringNewType(String), 13 | StructVariant { floats: Vec }, 14 | } 15 | 16 | fn main() { 17 | let settings = SchemaSettings::draft07().with(|s| { 18 | s.option_nullable = true; 19 | s.option_add_null_type = false; 20 | }); 21 | let generator = settings.into_generator(); 22 | let schema = generator.into_root_schema_for::(); 23 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /schemars/tests/dereference.rs: -------------------------------------------------------------------------------- 1 | use schemars::{r#gen::SchemaGenerator, JsonSchema}; 2 | use std::ptr; 3 | 4 | #[allow(dead_code)] 5 | #[derive(JsonSchema)] 6 | struct Struct { 7 | foo: i32, 8 | bar: bool, 9 | } 10 | 11 | #[test] 12 | fn dereference_struct() { 13 | let mut generator = SchemaGenerator::default(); 14 | let struct_ref_schema = generator.subschema_for::(); 15 | let struct_schema = generator.definitions().get(&::schema_name()).unwrap(); 16 | 17 | assert!(struct_ref_schema.is_ref()); 18 | assert!(!struct_schema.is_ref()); 19 | 20 | let dereferenced = generator.dereference(&struct_ref_schema); 21 | assert!(dereferenced.is_some()); 22 | assert!(ptr::eq(dereferenced.unwrap(), struct_schema)); 23 | } 24 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-enum-untagged.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Untagged", 4 | "anyOf": [ 5 | { 6 | "type": "object", 7 | "required": [ 8 | "foo" 9 | ], 10 | "properties": { 11 | "foo": { 12 | "type": "boolean" 13 | } 14 | } 15 | }, 16 | { 17 | "type": "boolean" 18 | }, 19 | { 20 | "type": "array", 21 | "items": [ 22 | { 23 | "type": "boolean" 24 | }, 25 | { 26 | "type": "integer", 27 | "format": "int32" 28 | } 29 | ], 30 | "maxItems": 2, 31 | "minItems": 2 32 | }, 33 | { 34 | "type": "boolean" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /schemars/tests/transparent.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | pub struct OuterStruct { 8 | inner: TransparentStruct, 9 | } 10 | 11 | #[allow(dead_code)] 12 | #[derive(JsonSchema)] 13 | #[serde(transparent)] 14 | pub struct TransparentStruct { 15 | #[serde(with = "TransparentNewType")] 16 | inner: (), 17 | } 18 | 19 | #[allow(dead_code)] 20 | #[derive(JsonSchema)] 21 | #[schemars(transparent)] 22 | pub struct TransparentNewType(Option); 23 | 24 | #[allow(dead_code)] 25 | #[derive(JsonSchema)] 26 | pub struct InnerStruct(String, i32); 27 | 28 | #[test] 29 | fn transparent_struct() -> TestResult { 30 | test_default_generated_schema::("transparent-struct") 31 | } 32 | -------------------------------------------------------------------------------- /docs/examples/6-doc_comments.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Doc Comments 4 | parent: Examples 5 | nav_order: 6 6 | summary: Giving schemas a custom title and/or description using doc comments. 7 | --- 8 | 9 | # Setting a Custom Title and/or Description Using Doc Comments 10 | 11 | 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`. 12 | 13 | {% include example.md name="doc_comments" %} 14 | -------------------------------------------------------------------------------- /schemars/tests/expected/nonzero_ints.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "nonzero_signed", 7 | "nonzero_unsigned", 8 | "signed", 9 | "unsigned" 10 | ], 11 | "properties": { 12 | "unsigned": { 13 | "type": "integer", 14 | "format": "uint32", 15 | "minimum": 0.0 16 | }, 17 | "nonzero_unsigned": { 18 | "type": "integer", 19 | "format": "uint32", 20 | "minimum": 1.0 21 | }, 22 | "signed": { 23 | "type": "integer", 24 | "format": "int32" 25 | }, 26 | "nonzero_signed": { 27 | "type": "integer", 28 | "format": "int32", 29 | "not": { 30 | "const": 0 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /schemars/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.8.27](https://github.com/oxc-project/schemars/compare/oxc-schemars-v0.8.26...oxc-schemars-v0.8.27) - 2025-11-23 11 | 12 | ### Fixed 13 | 14 | - Regenerate the test snapshots. ([#11](https://github.com/oxc-project/schemars/pull/11)) 15 | 16 | ### Other 17 | 18 | - Add a JSON Schema implementation for the regex crate ([#9](https://github.com/oxc-project/schemars/pull/9)) 19 | - Update examples/tests so they pass again. ([#8](https://github.com/oxc-project/schemars/pull/8)) 20 | -------------------------------------------------------------------------------- /schemars/tests/bound.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use std::marker::PhantomData; 3 | 4 | use schemars::JsonSchema; 5 | use util::*; 6 | 7 | struct MyIterator; 8 | 9 | impl Iterator for MyIterator { 10 | type Item = String; 11 | 12 | fn next(&mut self) -> Option { 13 | unimplemented!() 14 | } 15 | } 16 | 17 | // The default trait bounds would require T to implement JsonSchema, 18 | // which MyIterator does not. 19 | #[derive(JsonSchema)] 20 | #[schemars(bound = "T::Item: JsonSchema", rename = "MyContainer")] 21 | pub struct MyContainer 22 | where 23 | T: Iterator, 24 | { 25 | pub associated: T::Item, 26 | pub generic: PhantomData, 27 | } 28 | 29 | #[test] 30 | fn manual_bound_set() -> TestResult { 31 | test_default_generated_schema::>("bound") 32 | } 33 | -------------------------------------------------------------------------------- /schemars/tests/expected/doc_comments_struct_ref_siblings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "title": "This is the struct's title", 4 | "description": "This is the struct's description.", 5 | "type": "object", 6 | "required": [ 7 | "my_int", 8 | "my_undocumented_bool", 9 | "my_unit" 10 | ], 11 | "properties": { 12 | "my_int": { 13 | "title": "An integer", 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "my_undocumented_bool": { 18 | "type": "boolean" 19 | }, 20 | "my_unit": { 21 | "description": "A unit struct instance", 22 | "$ref": "#/definitions/MyUnitStruct" 23 | } 24 | }, 25 | "definitions": { 26 | "MyUnitStruct": { 27 | "title": "A Unit", 28 | "type": "null" 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /docs/_sass/custom/custom.scss: -------------------------------------------------------------------------------- 1 | // Reposition/resize top-right nav buttons 2 | .aux-nav a, .aux-nav a:hover { 3 | background: none; 4 | padding: 5px; 5 | } 6 | .aux-nav a img { 7 | height: 22px; 8 | } 9 | 10 | // Enlarge and compress embedded code 11 | pre.highlight, figure.highlight { 12 | line-height: 1.2em; 13 | } 14 | code { 15 | font-size: 14px; 16 | } 17 | 18 | // Always expand nav menu items 19 | .nav-list .nav-list-item > .nav-list { 20 | display: block; 21 | } 22 | .nav-list-expander { 23 | display: none; 24 | } 25 | 26 | // Indent text on attributes page 27 | .indented > p { 28 | margin-left: 20px; 29 | } 30 | 31 | // Hide ugly summary outline that chrome adds 32 | .main-content summary:focus { 33 | outline: none; 34 | } 35 | 36 | .main-content summary { 37 | display: list-item; 38 | font-style: italic; 39 | } -------------------------------------------------------------------------------- /schemars/tests/ui/invalid_validation_attrs.rs: -------------------------------------------------------------------------------- 1 | use schemars::JsonSchema; 2 | 3 | #[derive(JsonSchema)] 4 | pub struct Struct1(#[validate(regex = 0, foo, length(min = 1, equal = 2, bar))] String); 5 | 6 | #[derive(JsonSchema)] 7 | pub struct Struct2(#[schemars(regex = 0, foo, length(min = 1, equal = 2, bar))] String); 8 | 9 | #[derive(JsonSchema)] 10 | pub struct Struct3( 11 | #[validate( 12 | regex = "foo", 13 | contains = "bar", 14 | regex(path = "baz"), 15 | phone, 16 | email, 17 | url 18 | )] 19 | String, 20 | ); 21 | 22 | #[derive(JsonSchema)] 23 | pub struct Struct4( 24 | #[schemars( 25 | regex = "foo", 26 | contains = "bar", 27 | regex(path = "baz"), 28 | phone, 29 | email, 30 | url 31 | )] 32 | String, 33 | ); 34 | 35 | fn main() {} 36 | -------------------------------------------------------------------------------- /docs/examples/2-serde_attrs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Using Serde Attributes 4 | parent: Examples 5 | nav_order: 2 6 | summary: 'Deriving JsonSchema on types that use #[serde] attributes to customise serialization behaviour.' 7 | --- 8 | 9 | # Using Serde Attributes 10 | 11 | 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. 12 | 13 | The list of supported `#[serde]` attributes are [documented here]({{ site.baseurl }}{% link 1.1-attributes.md %}#supported-serde-attributes). 14 | 15 | {% include example.md name="serde_attrs" %} 16 | -------------------------------------------------------------------------------- /schemars/tests/expected/same_name.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Config2", 4 | "type": "object", 5 | "required": [ 6 | "a_cfg", 7 | "b_cfg" 8 | ], 9 | "properties": { 10 | "a_cfg": { 11 | "$ref": "#/definitions/Config" 12 | }, 13 | "b_cfg": { 14 | "$ref": "#/definitions/Config2" 15 | } 16 | }, 17 | "definitions": { 18 | "Config": { 19 | "type": "object", 20 | "required": [ 21 | "test" 22 | ], 23 | "properties": { 24 | "test": { 25 | "type": "string" 26 | } 27 | } 28 | }, 29 | "Config2": { 30 | "type": "object", 31 | "required": [ 32 | "test2" 33 | ], 34 | "properties": { 35 | "test2": { 36 | "type": "string" 37 | } 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | ci: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1 10 | - uses: oxc-project/setup-rust@ecabb7322a2ba5aeedb3612d2a40b86a85cee235 # v1.0.11 11 | with: 12 | save-cache: ${{ github.ref_name == 'main' }} 13 | cache-key: warm 14 | - name: Check with no feature flags 15 | run: cargo check --verbose --no-default-features 16 | working-directory: ./schemars 17 | - name: Run tests 18 | run: cargo test --verbose --all-features --no-fail-fast 19 | working-directory: ./schemars 20 | - name: Run derive tests 21 | run: cargo test --verbose --all-features --no-fail-fast 22 | working-directory: ./schemars_derive 23 | -------------------------------------------------------------------------------- /schemars/tests/expected/doc_comments_struct.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "This is the struct's title", 4 | "description": "This is the struct's description.", 5 | "type": "object", 6 | "required": [ 7 | "my_int", 8 | "my_undocumented_bool", 9 | "my_unit" 10 | ], 11 | "properties": { 12 | "my_int": { 13 | "title": "An integer", 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "my_undocumented_bool": { 18 | "type": "boolean" 19 | }, 20 | "my_unit": { 21 | "description": "A unit struct instance", 22 | "allOf": [ 23 | { 24 | "$ref": "#/definitions/MyUnitStruct" 25 | } 26 | ] 27 | } 28 | }, 29 | "definitions": { 30 | "MyUnitStruct": { 31 | "title": "A Unit", 32 | "type": "null" 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /docs/examples/9-from_value.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Generate Schema from Example Value 4 | parent: Examples 5 | nav_order: 9 6 | summary: >- 7 | Generating a schema for a serializable value. 8 | --- 9 | 10 | # Generate Schema from Example Value 11 | 12 | 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. 13 | 14 | {% include example.md name="from_value" %} 15 | 16 | Note that the schema for the enum is not very useful in this case, since schemars doesn't know anything about the second variant. 17 | -------------------------------------------------------------------------------- /schemars/tests/deprecated.rs: -------------------------------------------------------------------------------- 1 | #![allow(deprecated)] 2 | 3 | mod util; 4 | use schemars::JsonSchema; 5 | use util::*; 6 | 7 | #[allow(dead_code)] 8 | #[derive(JsonSchema)] 9 | #[deprecated] 10 | struct DeprecatedStruct { 11 | foo: i32, 12 | #[deprecated] 13 | deprecated_field: bool, 14 | } 15 | 16 | #[test] 17 | fn deprecated_struct() -> TestResult { 18 | test_default_generated_schema::("deprecated-struct") 19 | } 20 | 21 | #[allow(dead_code)] 22 | #[derive(JsonSchema)] 23 | #[deprecated] 24 | enum DeprecatedEnum { 25 | Unit, 26 | #[deprecated] 27 | DeprecatedUnitVariant, 28 | #[deprecated] 29 | DeprecatedStructVariant { 30 | foo: i32, 31 | #[deprecated] 32 | deprecated_field: bool, 33 | }, 34 | } 35 | 36 | #[test] 37 | fn deprecated_enum() -> TestResult { 38 | test_default_generated_schema::("deprecated-enum") 39 | } 40 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/either.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use either::Either; 5 | use std::borrow::Cow; 6 | 7 | impl JsonSchema for Either { 8 | no_ref_schema!(); 9 | 10 | fn schema_name() -> String { 11 | format!("Either_{}_or_{}", L::schema_name(), R::schema_name()) 12 | } 13 | 14 | fn schema_id() -> Cow<'static, str> { 15 | Cow::Owned(format!( 16 | "either::Either<{}, {}>", 17 | L::schema_id(), 18 | R::schema_id() 19 | )) 20 | } 21 | 22 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 23 | let mut schema = SchemaObject::default(); 24 | schema.subschemas().any_of = Some(vec![ 25 | generator.subschema_for::(), 26 | generator.subschema_for::(), 27 | ]); 28 | schema.into() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /schemars/tests/expected/chrono-types.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "ChronoTypes", 4 | "type": "object", 5 | "required": [ 6 | "date_time", 7 | "naive_date", 8 | "naive_date_time", 9 | "naive_time", 10 | "weekday" 11 | ], 12 | "properties": { 13 | "weekday": { 14 | "type": "string", 15 | "enum": [ 16 | "Mon", 17 | "Tue", 18 | "Wed", 19 | "Thu", 20 | "Fri", 21 | "Sat", 22 | "Sun" 23 | ] 24 | }, 25 | "date_time": { 26 | "type": "string", 27 | "format": "date-time" 28 | }, 29 | "naive_date": { 30 | "type": "string", 31 | "format": "date" 32 | }, 33 | "naive_date_time": { 34 | "type": "string", 35 | "format": "partial-date-time" 36 | }, 37 | "naive_time": { 38 | "type": "string", 39 | "format": "partial-date-time" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /schemars/examples/remote_derive.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Process", 4 | "type": "object", 5 | "required": [ 6 | "command_line", 7 | "durations", 8 | "wall_time" 9 | ], 10 | "properties": { 11 | "command_line": { 12 | "type": "string" 13 | }, 14 | "durations": { 15 | "type": "array", 16 | "items": { 17 | "$ref": "#/definitions/Duration" 18 | } 19 | }, 20 | "wall_time": { 21 | "$ref": "#/definitions/Duration" 22 | } 23 | }, 24 | "definitions": { 25 | "Duration": { 26 | "type": "object", 27 | "required": [ 28 | "nanos", 29 | "secs" 30 | ], 31 | "properties": { 32 | "nanos": { 33 | "type": "integer", 34 | "format": "int32" 35 | }, 36 | "secs": { 37 | "type": "integer", 38 | "format": "int64" 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docs/_includes/examples/remote_derive.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Process", 4 | "type": "object", 5 | "required": [ 6 | "command_line", 7 | "durations", 8 | "wall_time" 9 | ], 10 | "properties": { 11 | "command_line": { 12 | "type": "string" 13 | }, 14 | "durations": { 15 | "type": "array", 16 | "items": { 17 | "$ref": "#/definitions/Duration" 18 | } 19 | }, 20 | "wall_time": { 21 | "$ref": "#/definitions/Duration" 22 | } 23 | }, 24 | "definitions": { 25 | "Duration": { 26 | "type": "object", 27 | "required": [ 28 | "nanos", 29 | "secs" 30 | ], 31 | "properties": { 32 | "nanos": { 33 | "type": "integer", 34 | "format": "int32" 35 | }, 36 | "secs": { 37 | "type": "integer", 38 | "format": "int64" 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /schemars/examples/doc_comments.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | 3 | /// # My Amazing Struct 4 | /// This struct shows off generating a schema with 5 | /// a custom title and description. 6 | #[derive(JsonSchema)] 7 | pub struct MyStruct { 8 | /// # My Amazing Integer 9 | pub my_int: i32, 10 | /// This bool has a description, but no title. 11 | pub my_bool: bool, 12 | /// # A Nullable Enum 13 | /// This enum might be set, or it might not. 14 | pub my_nullable_enum: Option, 15 | } 16 | 17 | /// # My Amazing Enum 18 | #[derive(JsonSchema)] 19 | pub enum MyEnum { 20 | /// A wrapper around a `String` 21 | StringNewType(String), 22 | /// A struct-like enum variant which contains 23 | /// some floats 24 | StructVariant { 25 | /// The floats themselves 26 | floats: Vec, 27 | }, 28 | } 29 | 30 | fn main() { 31 | let schema = schema_for!(MyStruct); 32 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 33 | } 34 | -------------------------------------------------------------------------------- /schemars/examples/schemars_attrs.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Deserialize, Serialize, JsonSchema)] 5 | #[schemars(rename_all = "camelCase", deny_unknown_fields)] 6 | pub struct MyStruct { 7 | #[serde(rename = "thisIsOverridden")] 8 | #[schemars(rename = "myNumber", range(min = 1, max = 10))] 9 | pub my_int: i32, 10 | pub my_bool: bool, 11 | #[schemars(default)] 12 | pub my_nullable_enum: Option, 13 | #[schemars(inner(regex(pattern = "^x$")))] 14 | pub my_vec_str: Vec, 15 | } 16 | 17 | #[derive(Deserialize, Serialize, JsonSchema)] 18 | #[schemars(untagged)] 19 | pub enum MyEnum { 20 | StringNewType(#[schemars(phone)] String), 21 | StructVariant { 22 | #[schemars(length(min = 1, max = 100))] 23 | floats: Vec, 24 | }, 25 | } 26 | 27 | fn main() { 28 | let schema = schema_for!(MyStruct); 29 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 30 | } 31 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema-name-custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "a-new-name-Array_of_String-int32-int32", 4 | "type": "object", 5 | "required": [ 6 | "inner", 7 | "t", 8 | "u", 9 | "v", 10 | "w" 11 | ], 12 | "properties": { 13 | "t": { 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "u": { 18 | "type": "null" 19 | }, 20 | "v": { 21 | "type": "boolean" 22 | }, 23 | "w": { 24 | "type": "array", 25 | "items": { 26 | "type": "string" 27 | } 28 | }, 29 | "inner": { 30 | "$ref": "#/definitions/another-new-name" 31 | } 32 | }, 33 | "definitions": { 34 | "another-new-name": { 35 | "type": "object", 36 | "required": [ 37 | "foo" 38 | ], 39 | "properties": { 40 | "foo": { 41 | "type": "integer", 42 | "format": "int32" 43 | } 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /docs/_includes/examples/doc_comments.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | 3 | /// # My Amazing Struct 4 | /// This struct shows off generating a schema with 5 | /// a custom title and description. 6 | #[derive(JsonSchema)] 7 | pub struct MyStruct { 8 | /// # My Amazing Integer 9 | pub my_int: i32, 10 | /// This bool has a description, but no title. 11 | pub my_bool: bool, 12 | /// # A Nullable Enum 13 | /// This enum might be set, or it might not. 14 | pub my_nullable_enum: Option, 15 | } 16 | 17 | /// # My Amazing Enum 18 | #[derive(JsonSchema)] 19 | pub enum MyEnum { 20 | /// A wrapper around a `String` 21 | StringNewType(String), 22 | /// A struct-like enum variant which contains 23 | /// some floats 24 | StructVariant { 25 | /// The floats themselves 26 | floats: Vec, 27 | }, 28 | } 29 | 30 | fn main() { 31 | let schema = schema_for!(MyStruct); 32 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 33 | } 34 | -------------------------------------------------------------------------------- /docs/_includes/examples/schemars_attrs.rs: -------------------------------------------------------------------------------- 1 | use schemars::{schema_for, JsonSchema}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Deserialize, Serialize, JsonSchema)] 5 | #[schemars(rename_all = "camelCase", deny_unknown_fields)] 6 | pub struct MyStruct { 7 | #[serde(rename = "thisIsOverridden")] 8 | #[schemars(rename = "myNumber", range(min = 1, max = 10))] 9 | pub my_int: i32, 10 | pub my_bool: bool, 11 | #[schemars(default)] 12 | pub my_nullable_enum: Option, 13 | #[schemars(inner(regex(pattern = "^x$")))] 14 | pub my_vec_str: Vec, 15 | } 16 | 17 | #[derive(Deserialize, Serialize, JsonSchema)] 18 | #[schemars(untagged)] 19 | pub enum MyEnum { 20 | StringNewType(#[schemars(phone)] String), 21 | StructVariant { 22 | #[schemars(length(min = 1, max = 100))] 23 | floats: Vec, 24 | }, 25 | } 26 | 27 | fn main() { 28 | let schema = schema_for!(MyStruct); 29 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 30 | } 31 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema-name-default.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct_for_int32_and_Null_and_Boolean_and_Array_of_String", 4 | "type": "object", 5 | "required": [ 6 | "inner", 7 | "t", 8 | "u", 9 | "v", 10 | "w" 11 | ], 12 | "properties": { 13 | "t": { 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "u": { 18 | "type": "null" 19 | }, 20 | "v": { 21 | "type": "boolean" 22 | }, 23 | "w": { 24 | "type": "array", 25 | "items": { 26 | "type": "string" 27 | } 28 | }, 29 | "inner": { 30 | "$ref": "#/definitions/MySimpleStruct" 31 | } 32 | }, 33 | "definitions": { 34 | "MySimpleStruct": { 35 | "type": "object", 36 | "required": [ 37 | "foo" 38 | ], 39 | "properties": { 40 | "foo": { 41 | "type": "integer", 42 | "format": "int32" 43 | } 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /schemars/tests/expected/from_json_value.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "examples": [ 4 | { 5 | "bool": true, 6 | "minusOne": -1, 7 | "null": null, 8 | "object": { 9 | "array": [ 10 | "foo", 11 | "bar" 12 | ] 13 | }, 14 | "one": 1, 15 | "zero": 0, 16 | "zeroPointZero": 0.0 17 | } 18 | ], 19 | "type": "object", 20 | "properties": { 21 | "bool": { 22 | "type": "boolean" 23 | }, 24 | "minusOne": { 25 | "type": "integer" 26 | }, 27 | "null": true, 28 | "object": { 29 | "type": "object", 30 | "properties": { 31 | "array": { 32 | "type": "array", 33 | "items": { 34 | "type": "string" 35 | } 36 | } 37 | } 38 | }, 39 | "one": { 40 | "type": "integer" 41 | }, 42 | "zero": { 43 | "type": "integer" 44 | }, 45 | "zeroPointZero": { 46 | "type": "number" 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /schemars/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | // Based on https://github.com/serde-rs/serde/blob/master/serde/build.rs 4 | 5 | fn main() { 6 | let target = env::var("TARGET").unwrap(); 7 | let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; 8 | 9 | // Whitelist of archs that support std::sync::atomic module. Ideally we 10 | // would use #[cfg(target_has_atomic = "...")] but it is not stable yet. 11 | // Instead this is based on rustc's src/librustc_target/spec/*.rs. 12 | let has_atomic64 = target.starts_with("x86_64") 13 | || target.starts_with("i686") 14 | || target.starts_with("aarch64") 15 | || target.starts_with("powerpc64") 16 | || target.starts_with("sparc64") 17 | || target.starts_with("mips64el"); 18 | let has_atomic32 = has_atomic64 || emscripten; 19 | if has_atomic64 { 20 | println!("cargo:rustc-cfg=std_atomic64"); 21 | } 22 | if has_atomic32 { 23 | println!("cargo:rustc-cfg=std_atomic"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /schemars/tests/expected/enum-simple-internal.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "SimpleInternal", 4 | "oneOf": [ 5 | { 6 | "type": "object", 7 | "required": [ 8 | "typeProperty" 9 | ], 10 | "properties": { 11 | "typeProperty": { 12 | "type": "string", 13 | "enum": [ 14 | "A" 15 | ] 16 | } 17 | } 18 | }, 19 | { 20 | "type": "object", 21 | "required": [ 22 | "typeProperty" 23 | ], 24 | "properties": { 25 | "typeProperty": { 26 | "type": "string", 27 | "enum": [ 28 | "B" 29 | ] 30 | } 31 | } 32 | }, 33 | { 34 | "type": "object", 35 | "required": [ 36 | "typeProperty" 37 | ], 38 | "properties": { 39 | "typeProperty": { 40 | "type": "string", 41 | "enum": [ 42 | "C" 43 | ] 44 | } 45 | } 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /docs/examples/5-remote_derive.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Derive for Remote Crate 4 | parent: Examples 5 | nav_order: 5 6 | summary: Deriving JsonSchema implementations for a type in somebody else's crate. 7 | --- 8 | 9 | # Deriving JsonSchema for a Type in a Different Crate 10 | 11 | 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. 12 | 13 | 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. 14 | 15 | 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)! 16 | 17 | {% include example.md name="remote_derive" %} 18 | -------------------------------------------------------------------------------- /schemars/tests/struct.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | // Ensure that schemars_derive uses the full path to std::string::String 6 | pub struct String; 7 | 8 | #[allow(dead_code)] 9 | #[derive(JsonSchema)] 10 | struct Struct { 11 | foo: i32, 12 | bar: bool, 13 | baz: Option<&'static str>, 14 | } 15 | 16 | #[test] 17 | fn struct_normal() -> TestResult { 18 | test_default_generated_schema::("struct-normal") 19 | } 20 | 21 | #[allow(dead_code)] 22 | #[derive(JsonSchema)] 23 | pub struct Tuple(i32, bool, Option<&'static str>); 24 | 25 | #[test] 26 | fn struct_tuple() -> TestResult { 27 | test_default_generated_schema::("struct-tuple") 28 | } 29 | 30 | #[allow(dead_code)] 31 | #[derive(JsonSchema)] 32 | pub struct Newtype(i32); 33 | 34 | #[test] 35 | fn struct_newtype() -> TestResult { 36 | test_default_generated_schema::("struct-newtype") 37 | } 38 | 39 | #[derive(JsonSchema)] 40 | pub struct Unit; 41 | 42 | #[test] 43 | fn struct_unit() -> TestResult { 44 | test_default_generated_schema::("struct-unit") 45 | } 46 | -------------------------------------------------------------------------------- /schemars/tests/validate_inner.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | 3 | use schemars::JsonSchema; 4 | use util::*; 5 | 6 | // In real code, this would typically be a Regex, potentially created in a `lazy_static!`. 7 | static STARTS_WITH_HELLO: &str = r"^[Hh]ello\b"; 8 | 9 | #[allow(dead_code)] 10 | #[derive(JsonSchema)] 11 | pub struct Struct<'a> { 12 | #[schemars(inner(length(min = 5, max = 100)))] 13 | array_str_length: [&'a str; 2], 14 | #[schemars(inner(contains(pattern = "substring...")))] 15 | slice_str_contains: &'a [&'a str], 16 | #[schemars(inner(regex = "STARTS_WITH_HELLO"))] 17 | vec_str_regex: Vec, 18 | #[schemars(inner(length(min = 1, max = 100)))] 19 | vec_str_length: Vec<&'a str>, 20 | #[schemars(length(min = 1, max = 3), inner(length(min = 1, max = 100)))] 21 | vec_str_length2: Vec, 22 | #[schemars(inner(url))] 23 | vec_str_url: Vec, 24 | #[schemars(inner(range(min = -10, max = 10)))] 25 | vec_i32_range: Vec, 26 | } 27 | 28 | #[test] 29 | fn validate_inner() -> TestResult { 30 | test_default_generated_schema::("validate_inner") 31 | } 32 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/semver.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use semver::Version; 5 | use std::borrow::Cow; 6 | 7 | impl JsonSchema for Version { 8 | no_ref_schema!(); 9 | 10 | fn schema_name() -> String { 11 | "Version".to_owned() 12 | } 13 | 14 | fn schema_id() -> Cow<'static, str> { 15 | Cow::Borrowed("semver::Version") 16 | } 17 | 18 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 19 | SchemaObject { 20 | instance_type: Some(InstanceType::String.into()), 21 | string: Some(Box::new(StringValidation { 22 | // https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string 23 | pattern: Some(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$".to_owned()), 24 | ..Default::default() 25 | })), 26 | ..Default::default() 27 | } 28 | .into() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /schemars/tests/inline_subschemas.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::r#gen::SchemaSettings; 3 | use schemars::JsonSchema; 4 | use util::*; 5 | 6 | #[allow(dead_code)] 7 | #[derive(JsonSchema)] 8 | struct MyJob { 9 | spec: MyJobSpec, 10 | } 11 | 12 | #[allow(dead_code)] 13 | #[derive(JsonSchema)] 14 | struct MyJobSpec { 15 | replicas: u32, 16 | } 17 | 18 | #[test] 19 | fn struct_normal() -> TestResult { 20 | let mut settings = SchemaSettings::default(); 21 | settings.inline_subschemas = true; 22 | test_generated_schema::("inline-subschemas", settings) 23 | } 24 | 25 | #[allow(dead_code)] 26 | #[derive(JsonSchema)] 27 | struct RecursiveOuter { 28 | direct: Option>, 29 | indirect: Option>, 30 | } 31 | 32 | #[allow(dead_code)] 33 | #[derive(JsonSchema)] 34 | struct RecursiveInner { 35 | recursive: RecursiveOuter, 36 | } 37 | 38 | #[test] 39 | fn struct_recursive() -> TestResult { 40 | let mut settings = SchemaSettings::default(); 41 | settings.inline_subschemas = true; 42 | test_generated_schema::("inline-subschemas-recursive", settings) 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Graham Esau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /schemars/tests/expected/deprecated-enum.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "DeprecatedEnum", 4 | "deprecated": true, 5 | "oneOf": [ 6 | { 7 | "type": "string", 8 | "enum": [ 9 | "Unit" 10 | ] 11 | }, 12 | { 13 | "deprecated": true, 14 | "type": "string", 15 | "enum": [ 16 | "DeprecatedUnitVariant" 17 | ] 18 | }, 19 | { 20 | "deprecated": true, 21 | "type": "object", 22 | "required": [ 23 | "DeprecatedStructVariant" 24 | ], 25 | "properties": { 26 | "DeprecatedStructVariant": { 27 | "type": "object", 28 | "required": [ 29 | "deprecated_field", 30 | "foo" 31 | ], 32 | "properties": { 33 | "deprecated_field": { 34 | "deprecated": true, 35 | "type": "boolean" 36 | }, 37 | "foo": { 38 | "type": "integer", 39 | "format": "int32" 40 | } 41 | } 42 | } 43 | }, 44 | "additionalProperties": false 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/arrayvec07.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use arrayvec07::{ArrayString, ArrayVec}; 5 | use std::convert::TryInto; 6 | 7 | // Do not set maxLength on the schema as that describes length in characters, but we only 8 | // know max length in bytes. 9 | forward_impl!(( JsonSchema for ArrayString) => String); 10 | 11 | impl JsonSchema for ArrayVec 12 | where 13 | T: JsonSchema, 14 | { 15 | no_ref_schema!(); 16 | 17 | fn schema_name() -> String { 18 | format!("Array_up_to_size_{}_of_{}", CAP, T::schema_name()) 19 | } 20 | 21 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 22 | SchemaObject { 23 | instance_type: Some(InstanceType::Array.into()), 24 | array: Some(Box::new(ArrayValidation { 25 | items: Some(generator.subschema_for::().into()), 26 | max_items: CAP.try_into().ok(), 27 | ..Default::default() 28 | })), 29 | ..Default::default() 30 | } 31 | .into() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /schemars/tests/expected/enum-simple-internal-duf.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "SimpleInternal", 4 | "oneOf": [ 5 | { 6 | "type": "object", 7 | "required": [ 8 | "typeProperty" 9 | ], 10 | "properties": { 11 | "typeProperty": { 12 | "type": "string", 13 | "enum": [ 14 | "A" 15 | ] 16 | } 17 | }, 18 | "additionalProperties": false 19 | }, 20 | { 21 | "type": "object", 22 | "required": [ 23 | "typeProperty" 24 | ], 25 | "properties": { 26 | "typeProperty": { 27 | "type": "string", 28 | "enum": [ 29 | "B" 30 | ] 31 | } 32 | }, 33 | "additionalProperties": false 34 | }, 35 | { 36 | "type": "object", 37 | "required": [ 38 | "typeProperty" 39 | ], 40 | "properties": { 41 | "typeProperty": { 42 | "type": "string", 43 | "enum": [ 44 | "C" 45 | ] 46 | } 47 | }, 48 | "additionalProperties": false 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/wrapper.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::Schema; 3 | use crate::JsonSchema; 4 | 5 | macro_rules! wrapper_impl { 6 | ($($desc:tt)+) => { 7 | forward_impl!(($($desc)+ where T: JsonSchema) => T); 8 | }; 9 | } 10 | 11 | wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a T); 12 | wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a mut T); 13 | wrapper_impl!( JsonSchema for Box); 14 | wrapper_impl!( JsonSchema for std::rc::Rc); 15 | wrapper_impl!( JsonSchema for std::rc::Weak); 16 | wrapper_impl!( JsonSchema for std::sync::Arc); 17 | wrapper_impl!( JsonSchema for std::sync::Weak); 18 | wrapper_impl!( JsonSchema for std::sync::Mutex); 19 | wrapper_impl!( JsonSchema for std::sync::RwLock); 20 | wrapper_impl!( JsonSchema for std::cell::Cell); 21 | wrapper_impl!( JsonSchema for std::cell::RefCell); 22 | wrapper_impl!(<'a, T: ?Sized + ToOwned> JsonSchema for std::borrow::Cow<'a, T>); 23 | wrapper_impl!( JsonSchema for std::num::Wrapping); 24 | wrapper_impl!( JsonSchema for std::cmp::Reverse); 25 | -------------------------------------------------------------------------------- /schemars/tests/remote_derive.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | 3 | use other_crate::Duration; 4 | use schemars::JsonSchema; 5 | use serde::Serialize; 6 | use util::*; 7 | 8 | mod other_crate { 9 | #[derive(Default)] 10 | pub struct Duration { 11 | pub secs: i64, 12 | pub nanos: i32, 13 | } 14 | } 15 | 16 | #[derive(JsonSchema, Serialize)] 17 | #[serde(remote = "Duration")] 18 | struct DurationDef { 19 | secs: i64, 20 | nanos: i32, 21 | } 22 | 23 | fn custom_serialize(value: &Duration, ser: S) -> Result 24 | where 25 | S: serde::Serializer, 26 | { 27 | ser.collect_str(&format_args!("{}.{:09}s", value.secs, value.nanos)) 28 | } 29 | 30 | #[derive(JsonSchema, Serialize)] 31 | struct Process { 32 | command_line: String, 33 | #[serde(with = "DurationDef")] 34 | wall_time: Duration, 35 | #[serde(default, with = "DurationDef")] 36 | user_cpu_time: Duration, 37 | #[serde(default, serialize_with = "custom_serialize")] 38 | #[schemars(with = "DurationDef")] 39 | system_cpu_time: Duration, 40 | } 41 | 42 | #[test] 43 | fn remote_derive_json_schema() -> TestResult { 44 | test_default_generated_schema::("remote_derive") 45 | } 46 | -------------------------------------------------------------------------------- /schemars/examples/serde_attrs.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "myBool", 7 | "myNumber" 8 | ], 9 | "properties": { 10 | "myBool": { 11 | "type": "boolean" 12 | }, 13 | "myNullableEnum": { 14 | "default": null, 15 | "anyOf": [ 16 | { 17 | "$ref": "#/definitions/MyEnum" 18 | }, 19 | { 20 | "type": "null" 21 | } 22 | ] 23 | }, 24 | "myNumber": { 25 | "type": "integer", 26 | "format": "int32" 27 | } 28 | }, 29 | "additionalProperties": false, 30 | "definitions": { 31 | "MyEnum": { 32 | "anyOf": [ 33 | { 34 | "type": "string" 35 | }, 36 | { 37 | "type": "object", 38 | "required": [ 39 | "floats" 40 | ], 41 | "properties": { 42 | "floats": { 43 | "type": "array", 44 | "items": { 45 | "type": "number", 46 | "format": "float" 47 | } 48 | } 49 | } 50 | } 51 | ] 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /schemars/tests/ui/invalid_attrs.stderr: -------------------------------------------------------------------------------- 1 | error: expected serde default attribute to be a string: `default = "..."` 2 | --> $DIR/invalid_attrs.rs:4:19 3 | | 4 | 4 | #[serde(default = 0, foo, deny_unknown_fields, deny_unknown_fields)] 5 | | ^ 6 | 7 | error: duplicate serde attribute `deny_unknown_fields` 8 | --> $DIR/invalid_attrs.rs:4:48 9 | | 10 | 4 | #[serde(default = 0, foo, deny_unknown_fields, deny_unknown_fields)] 11 | | ^^^^^^^^^^^^^^^^^^^ 12 | 13 | error: expected serde default attribute to be a string: `default = "..."` 14 | --> $DIR/invalid_attrs.rs:8:22 15 | | 16 | 8 | #[schemars(default = 0, foo, deny_unknown_fields, deny_unknown_fields)] 17 | | ^ 18 | 19 | error: duplicate serde attribute `deny_unknown_fields` 20 | --> $DIR/invalid_attrs.rs:8:51 21 | | 22 | 8 | #[schemars(default = 0, foo, deny_unknown_fields, deny_unknown_fields)] 23 | | ^^^^^^^^^^^^^^^^^^^ 24 | 25 | error: unknown schemars attribute `foo` 26 | --> $DIR/invalid_attrs.rs:8:25 27 | | 28 | 8 | #[schemars(default = 0, foo, deny_unknown_fields, deny_unknown_fields)] 29 | | ^^^ 30 | -------------------------------------------------------------------------------- /docs/_includes/examples/serde_attrs.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "myBool", 7 | "myNumber" 8 | ], 9 | "properties": { 10 | "myBool": { 11 | "type": "boolean" 12 | }, 13 | "myNullableEnum": { 14 | "default": null, 15 | "anyOf": [ 16 | { 17 | "$ref": "#/definitions/MyEnum" 18 | }, 19 | { 20 | "type": "null" 21 | } 22 | ] 23 | }, 24 | "myNumber": { 25 | "type": "integer", 26 | "format": "int32" 27 | } 28 | }, 29 | "additionalProperties": false, 30 | "definitions": { 31 | "MyEnum": { 32 | "anyOf": [ 33 | { 34 | "type": "string" 35 | }, 36 | { 37 | "type": "object", 38 | "required": [ 39 | "floats" 40 | ], 41 | "properties": { 42 | "floats": { 43 | "type": "array", 44 | "items": { 45 | "type": "number", 46 | "format": "float" 47 | } 48 | } 49 | } 50 | } 51 | ] 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /schemars/tests/flatten.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | struct Flat { 8 | f: f32, 9 | b: bool, 10 | s: String, 11 | #[serde(default)] 12 | os: String, 13 | v: Vec, 14 | } 15 | 16 | #[allow(dead_code)] 17 | #[derive(JsonSchema)] 18 | #[schemars(rename = "Flat")] 19 | struct Deep1 { 20 | f: f32, 21 | #[schemars(flatten)] 22 | deep2: Deep2, 23 | v: Vec, 24 | } 25 | 26 | #[allow(clippy::option_option, dead_code)] 27 | #[derive(JsonSchema)] 28 | struct Deep2 { 29 | b: bool, 30 | #[serde(flatten)] 31 | deep3: Deep3, 32 | #[serde(flatten)] 33 | deep4: Box>>>, 34 | } 35 | 36 | #[allow(dead_code)] 37 | #[derive(JsonSchema)] 38 | struct Deep3 { 39 | s: &'static str, 40 | } 41 | 42 | #[allow(dead_code)] 43 | #[derive(JsonSchema)] 44 | struct Deep4 { 45 | #[serde(default)] 46 | os: &'static str, 47 | } 48 | 49 | #[test] 50 | fn test_flat_schema() -> TestResult { 51 | test_default_generated_schema::("flatten") 52 | } 53 | 54 | #[test] 55 | fn test_flattened_schema() -> TestResult { 56 | test_default_generated_schema::("flatten") 57 | } 58 | -------------------------------------------------------------------------------- /schemars/tests/expected/remote_derive.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Process", 4 | "type": "object", 5 | "required": [ 6 | "command_line", 7 | "wall_time" 8 | ], 9 | "properties": { 10 | "command_line": { 11 | "type": "string" 12 | }, 13 | "wall_time": { 14 | "$ref": "#/definitions/Duration" 15 | }, 16 | "user_cpu_time": { 17 | "default": { 18 | "nanos": 0, 19 | "secs": 0 20 | }, 21 | "allOf": [ 22 | { 23 | "$ref": "#/definitions/Duration" 24 | } 25 | ] 26 | }, 27 | "system_cpu_time": { 28 | "default": "0.000000000s", 29 | "allOf": [ 30 | { 31 | "$ref": "#/definitions/Duration" 32 | } 33 | ] 34 | } 35 | }, 36 | "definitions": { 37 | "Duration": { 38 | "type": "object", 39 | "required": [ 40 | "nanos", 41 | "secs" 42 | ], 43 | "properties": { 44 | "secs": { 45 | "type": "integer", 46 | "format": "int64" 47 | }, 48 | "nanos": { 49 | "type": "integer", 50 | "format": "int32" 51 | } 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /docs/1-deriving.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Deriving JsonSchema 4 | nav_order: 2 5 | has_children: true 6 | has_toc: false 7 | permalink: /deriving/ 8 | --- 9 | 10 | # Deriving JsonSchema 11 | 12 | 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. 13 | 14 | Usually, all you need to do to use it is to add a `#[derive(JsonSchema)]` attribute to your type: 15 | ```rust 16 | use schemars::{JsonSchema, schema_for}; 17 | 18 | #[derive(JsonSchema, Debug)] 19 | struct Point { 20 | x: i32, 21 | y: i32, 22 | } 23 | 24 | fn main() { 25 | let schema = schema_for!(Point); 26 | 27 | let serialized = serde_json::to_string(&schema).unwrap(); 28 | println!("{}", serialized); 29 | } 30 | ``` 31 | 36 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | # Hello! This is where you manage which Jekyll version is used to run. 3 | # When you want to use a different version, change it below, save the 4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # This will help ensure the proper Jekyll version is running. 9 | # Happy Jekylling! 10 | # gem "jekyll", "~> 4.0.0" 11 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 12 | # gem "minima", "~> 2.5" 13 | gem "just-the-docs", "= 0.10.1" 14 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 15 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 16 | gem "github-pages", group: :jekyll_plugins 17 | # If you have any plugins, put them here! 18 | group :jekyll_plugins do 19 | end 20 | 21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem 22 | # and associated library. 23 | install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do 24 | gem "tzinfo", "~> 2.0" 25 | gem "tzinfo-data" 26 | end 27 | 28 | # Performance-booster for watching directories on Windows 29 | gem "wdm", "~> 0.2.0", :install_if => Gem.win_platform? 30 | 31 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-enum-internal.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Internal", 4 | "oneOf": [ 5 | { 6 | "type": "object", 7 | "required": [ 8 | "foo", 9 | "typeProperty" 10 | ], 11 | "properties": { 12 | "foo": { 13 | "type": "boolean" 14 | }, 15 | "typeProperty": { 16 | "type": "string", 17 | "enum": [ 18 | "Struct" 19 | ] 20 | } 21 | } 22 | }, 23 | { 24 | "type": [ 25 | "boolean", 26 | "object" 27 | ], 28 | "required": [ 29 | "typeProperty" 30 | ], 31 | "properties": { 32 | "typeProperty": { 33 | "type": "string", 34 | "enum": [ 35 | "NewType" 36 | ] 37 | } 38 | } 39 | }, 40 | { 41 | "type": [ 42 | "boolean", 43 | "object" 44 | ], 45 | "required": [ 46 | "typeProperty" 47 | ], 48 | "properties": { 49 | "typeProperty": { 50 | "type": "string", 51 | "enum": [ 52 | "Unit" 53 | ] 54 | } 55 | } 56 | } 57 | ] 58 | } -------------------------------------------------------------------------------- /docs/examples/7-custom_serialization.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Custom Serialization 4 | parent: Examples 5 | nav_order: 7 6 | summary: >- 7 | If a field has a #[serde(with = "path")] attribute where "path" is not a type that implements JsonSchema, 8 | then in order to derive JsonSchema on the type, it must also have a #[schemars(with = "Type")] attribute, 9 | where "Type" implements JsonSchema. 10 | --- 11 | 12 | # Deriving JsonSchema with Fields Using Custom Serialization 13 | 14 | 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`. 15 | 16 | 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. 17 | 18 | {% include example.md name="custom_serialization" %} 19 | 20 | Note that the `default` values in the schema are serialized as strings where appropriate. 21 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/serdejson.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use serde_json::{Map, Number, Value}; 5 | use std::borrow::Cow; 6 | use std::collections::BTreeMap; 7 | 8 | impl JsonSchema for Value { 9 | no_ref_schema!(); 10 | 11 | fn schema_name() -> String { 12 | "AnyValue".to_owned() 13 | } 14 | 15 | fn schema_id() -> Cow<'static, str> { 16 | Cow::Borrowed("AnyValue") 17 | } 18 | 19 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 20 | Schema::Bool(true) 21 | } 22 | } 23 | 24 | forward_impl!(Map => BTreeMap); 25 | 26 | impl JsonSchema for Number { 27 | no_ref_schema!(); 28 | 29 | fn schema_name() -> String { 30 | "Number".to_owned() 31 | } 32 | 33 | fn schema_id() -> Cow<'static, str> { 34 | Cow::Borrowed("Number") 35 | } 36 | 37 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 38 | SchemaObject { 39 | instance_type: Some(InstanceType::Number.into()), 40 | ..Default::default() 41 | } 42 | .into() 43 | } 44 | } 45 | 46 | #[cfg(feature = "raw_value")] 47 | forward_impl!(serde_json::value::RawValue => Value); 48 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/arrayvec05.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use arrayvec05::{Array, ArrayString, ArrayVec}; 5 | use std::convert::TryInto; 6 | 7 | // Do not set maxLength on the schema as that describes length in characters, but we only 8 | // know max length in bytes. 9 | forward_impl!((
JsonSchema for ArrayString where A: Array + Copy) => String); 10 | 11 | impl JsonSchema for ArrayVec 12 | where 13 | A::Item: JsonSchema, 14 | { 15 | no_ref_schema!(); 16 | 17 | fn schema_name() -> String { 18 | format!( 19 | "Array_up_to_size_{}_of_{}", 20 | A::CAPACITY, 21 | A::Item::schema_name() 22 | ) 23 | } 24 | 25 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 26 | SchemaObject { 27 | instance_type: Some(InstanceType::Array.into()), 28 | array: Some(Box::new(ArrayValidation { 29 | items: Some(generator.subschema_for::().into()), 30 | max_items: A::CAPACITY.try_into().ok(), 31 | ..Default::default() 32 | })), 33 | ..Default::default() 34 | } 35 | .into() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Overview 4 | nav_order: 1 5 | --- 6 | 7 | # Schemars 8 | 9 | Schemars is a library to generate JSON Schema documents from Rust data structures. 10 | 11 | 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. 12 | 13 | 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. 14 | 15 | ## Basic Usage 16 | 17 | 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. 18 | 19 | {% include example.md name="main" %} 20 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/decimal.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | 6 | macro_rules! decimal_impl { 7 | ($type:ty) => { 8 | impl JsonSchema for $type { 9 | no_ref_schema!(); 10 | 11 | fn schema_name() -> String { 12 | "Decimal".to_owned() 13 | } 14 | 15 | fn schema_id() -> Cow<'static, str> { 16 | Cow::Borrowed("Decimal") 17 | } 18 | 19 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 20 | SchemaObject { 21 | instance_type: Some(InstanceType::String.into()), 22 | string: Some(Box::new(StringValidation { 23 | pattern: Some(r"^-?[0-9]+(\.[0-9]+)?$".to_owned()), 24 | ..Default::default() 25 | })), 26 | ..Default::default() 27 | } 28 | .into() 29 | } 30 | } 31 | }; 32 | } 33 | 34 | #[cfg(feature = "rust_decimal")] 35 | decimal_impl!(rust_decimal::Decimal); 36 | #[cfg(feature = "bigdecimal03")] 37 | decimal_impl!(bigdecimal03::BigDecimal); 38 | #[cfg(feature = "bigdecimal04")] 39 | decimal_impl!(bigdecimal04::BigDecimal); 40 | -------------------------------------------------------------------------------- /schemars/tests/expected/doc_comments_enum.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "This is the enum's title", 4 | "description": "This is\nthe enum's description.", 5 | "oneOf": [ 6 | { 7 | "type": "string", 8 | "enum": [ 9 | "UndocumentedUnit", 10 | "UndocumentedUnit2" 11 | ] 12 | }, 13 | { 14 | "description": "This comment is included in the generated schema :)", 15 | "type": "string", 16 | "enum": [ 17 | "DocumentedUnit" 18 | ] 19 | }, 20 | { 21 | "title": "Complex variant", 22 | "description": "This is a struct-like variant.", 23 | "type": "object", 24 | "required": [ 25 | "Complex" 26 | ], 27 | "properties": { 28 | "Complex": { 29 | "type": "object", 30 | "properties": { 31 | "my_nullable_string": { 32 | "title": "A nullable string", 33 | "description": "This field is a nullable string.\n\nThis\nis\nthe second\nline!\n\n\n\n\nAnd this is the third!", 34 | "type": [ 35 | "string", 36 | "null" 37 | ] 38 | } 39 | } 40 | } 41 | }, 42 | "additionalProperties": false 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /schemars/tests/expected/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "properties": { 6 | "my_int": { 7 | "default": 0, 8 | "type": "integer", 9 | "format": "int32" 10 | }, 11 | "my_bool": { 12 | "default": false, 13 | "type": "boolean" 14 | }, 15 | "my_optional_string": { 16 | "default": null, 17 | "type": [ 18 | "string", 19 | "null" 20 | ] 21 | }, 22 | "my_struct2": { 23 | "default": "i:0 b:false", 24 | "allOf": [ 25 | { 26 | "$ref": "#/definitions/MyStruct2" 27 | } 28 | ] 29 | }, 30 | "my_struct2_default_skipped": { 31 | "$ref": "#/definitions/MyStruct2" 32 | }, 33 | "not_serialize": { 34 | "$ref": "#/definitions/NotSerialize" 35 | } 36 | }, 37 | "definitions": { 38 | "MyStruct2": { 39 | "type": "object", 40 | "properties": { 41 | "my_int": { 42 | "default": 6, 43 | "type": "integer", 44 | "format": "int32" 45 | }, 46 | "my_bool": { 47 | "default": true, 48 | "type": "boolean" 49 | } 50 | } 51 | }, 52 | "NotSerialize": { 53 | "type": "null" 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /schemars/tests/expected/os_strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "OsStrings", 4 | "type": "object", 5 | "required": [ 6 | "borrowed", 7 | "owned" 8 | ], 9 | "properties": { 10 | "owned": { 11 | "$ref": "#/definitions/OsString" 12 | }, 13 | "borrowed": { 14 | "$ref": "#/definitions/OsString" 15 | } 16 | }, 17 | "definitions": { 18 | "OsString": { 19 | "oneOf": [ 20 | { 21 | "type": "object", 22 | "required": [ 23 | "Unix" 24 | ], 25 | "properties": { 26 | "Unix": { 27 | "type": "array", 28 | "items": { 29 | "type": "integer", 30 | "format": "uint8", 31 | "minimum": 0.0 32 | } 33 | } 34 | } 35 | }, 36 | { 37 | "type": "object", 38 | "required": [ 39 | "Windows" 40 | ], 41 | "properties": { 42 | "Windows": { 43 | "type": "array", 44 | "items": { 45 | "type": "integer", 46 | "format": "uint16", 47 | "minimum": 0.0 48 | } 49 | } 50 | } 51 | } 52 | ] 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /schemars/tests/skip.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | struct MyStruct { 8 | #[schemars(skip)] 9 | skipped1: i32, 10 | #[serde(skip)] 11 | skipped2: bool, 12 | #[serde(skip_deserializing)] 13 | readable: String, 14 | #[serde(skip_serializing)] 15 | writable: f32, 16 | included: (), 17 | } 18 | 19 | #[test] 20 | fn skip_struct_fields() -> TestResult { 21 | test_default_generated_schema::("skip_struct_fields") 22 | } 23 | 24 | #[allow(dead_code)] 25 | #[derive(JsonSchema)] 26 | struct TupleStruct( 27 | #[schemars(skip)] i32, 28 | #[serde(skip)] bool, 29 | #[serde(skip_deserializing)] String, 30 | #[serde(skip_serializing)] f32, 31 | (), 32 | ); 33 | 34 | #[test] 35 | fn skip_tuple_fields() -> TestResult { 36 | test_default_generated_schema::("skip_tuple_fields") 37 | } 38 | 39 | #[derive(JsonSchema)] 40 | pub enum MyEnum { 41 | #[schemars(skip)] 42 | Skipped1(i32), 43 | #[serde(skip)] 44 | Skipped2, 45 | #[serde(skip_deserializing)] 46 | Skipped3, 47 | #[serde(skip_serializing)] 48 | Included1(f32), 49 | Included2, 50 | } 51 | 52 | #[test] 53 | fn skip_enum_variants() -> TestResult { 54 | test_default_generated_schema::("skip_enum_variants") 55 | } 56 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/maps.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | 6 | macro_rules! map_impl { 7 | ($($desc:tt)+) => { 8 | impl $($desc)+ 9 | where 10 | V: JsonSchema, 11 | { 12 | no_ref_schema!(); 13 | 14 | fn schema_name() -> String { 15 | format!("Map_of_{}", V::schema_name()) 16 | } 17 | 18 | fn schema_id() -> Cow<'static, str> { 19 | Cow::Owned(format!("Map<{}>", V::schema_id())) 20 | } 21 | 22 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 23 | let subschema = generator.subschema_for::(); 24 | SchemaObject { 25 | instance_type: Some(InstanceType::Object.into()), 26 | object: Some(Box::new(ObjectValidation { 27 | additional_properties: Some(Box::new(subschema)), 28 | ..Default::default() 29 | })), 30 | ..Default::default() 31 | } 32 | .into() 33 | } 34 | } 35 | }; 36 | } 37 | 38 | map_impl!( JsonSchema for std::collections::BTreeMap); 39 | map_impl!( JsonSchema for std::collections::HashMap); 40 | -------------------------------------------------------------------------------- /schemars/tests/remote_derive_generic.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | 3 | use schemars::JsonSchema; 4 | use serde::Serialize; 5 | use std::collections::{HashMap, HashSet}; 6 | use util::*; 7 | 8 | #[allow(dead_code)] 9 | enum Or { 10 | A(A), 11 | B(B), 12 | } 13 | 14 | #[derive(JsonSchema, Serialize)] 15 | #[serde(untagged, remote = "Or")] 16 | enum OrDef { 17 | A(A), 18 | B(B), 19 | } 20 | 21 | struct Str<'a>(&'a str); 22 | 23 | #[allow(dead_code)] 24 | #[derive(JsonSchema, Serialize)] 25 | #[serde(remote = "Str")] 26 | struct StrDef<'a>(&'a str); 27 | 28 | #[derive(JsonSchema, Serialize)] 29 | struct MyStruct<'a, T: Serialize> { 30 | // #[serde(with = "OrDef::<_, _>")] 31 | // byte_or_bool1: Or, 32 | #[serde(with = "OrDef::")] 33 | byte_or_bool2: Or, 34 | // #[serde(with = "OrDef::<_, _>")] 35 | // unit_or_t1: Or<(), T>, 36 | #[serde(with = "OrDef::<(), T>")] 37 | unit_or_t2: Or<(), T>, 38 | #[serde(borrow, with = "StrDef")] 39 | s: Str<'a>, 40 | // #[schemars(with = "HashMap::<_, HashSet<_>>")] 41 | // map: BTreeMap>, 42 | #[schemars(with = "HashMap::>")] 43 | fake_map: (), 44 | } 45 | 46 | #[test] 47 | fn remote_derive_json_schema() -> TestResult { 48 | test_default_generated_schema::>("remote_derive_generic") 49 | } 50 | -------------------------------------------------------------------------------- /schemars/tests/expected/duration_and_systemtime.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "duration", 7 | "time" 8 | ], 9 | "properties": { 10 | "duration": { 11 | "$ref": "#/definitions/Duration" 12 | }, 13 | "time": { 14 | "$ref": "#/definitions/SystemTime" 15 | } 16 | }, 17 | "definitions": { 18 | "Duration": { 19 | "type": "object", 20 | "required": [ 21 | "nanos", 22 | "secs" 23 | ], 24 | "properties": { 25 | "secs": { 26 | "type": "integer", 27 | "format": "uint64", 28 | "minimum": 0.0 29 | }, 30 | "nanos": { 31 | "type": "integer", 32 | "format": "uint32", 33 | "minimum": 0.0 34 | } 35 | } 36 | }, 37 | "SystemTime": { 38 | "type": "object", 39 | "required": [ 40 | "nanos_since_epoch", 41 | "secs_since_epoch" 42 | ], 43 | "properties": { 44 | "secs_since_epoch": { 45 | "type": "integer", 46 | "format": "uint64", 47 | "minimum": 0.0 48 | }, 49 | "nanos_since_epoch": { 50 | "type": "integer", 51 | "format": "uint32", 52 | "minimum": 0.0 53 | } 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /schemars/tests/schema_settings.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::r#gen::SchemaSettings; 3 | use schemars::JsonSchema; 4 | use serde_json::Value; 5 | use std::collections::BTreeMap; 6 | use util::*; 7 | 8 | #[derive(JsonSchema)] 9 | pub struct Outer { 10 | #[schemars(example = "eight", example = "null")] 11 | pub int: i32, 12 | pub values: BTreeMap<&'static str, Value>, 13 | pub value: Value, 14 | pub inner: Option, 15 | } 16 | 17 | #[derive(JsonSchema)] 18 | pub enum Inner { 19 | UndocumentedUnit1, 20 | UndocumentedUnit2, 21 | /// This is a documented unit variant 22 | DocumentedUnit, 23 | ValueNewType(Value), 24 | } 25 | 26 | fn eight() -> i32 { 27 | 8 28 | } 29 | 30 | fn null() {} 31 | 32 | #[test] 33 | fn schema_matches_draft07() -> TestResult { 34 | test_generated_schema::("schema_settings", SchemaSettings::draft07()) 35 | } 36 | 37 | #[test] 38 | fn schema_matches_2019_09() -> TestResult { 39 | test_generated_schema::("schema_settings-2019_09", SchemaSettings::draft2019_09()) 40 | } 41 | 42 | #[test] 43 | #[ignore = "Fails due to default/empty `Metadata` not being considered equal to `Option::None`, although they're conceptually the same and serialize to identical JSON"] 44 | fn schema_matches_openapi3() -> TestResult { 45 | test_generated_schema::("schema_settings-openapi3", SchemaSettings::openapi3()) 46 | } 47 | -------------------------------------------------------------------------------- /schemars/tests/expected/remote_derive_generic.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct_for_int32", 4 | "type": "object", 5 | "required": [ 6 | "byte_or_bool2", 7 | "fake_map", 8 | "s", 9 | "unit_or_t2" 10 | ], 11 | "properties": { 12 | "byte_or_bool2": { 13 | "$ref": "#/definitions/Or_for_uint8_and_Boolean" 14 | }, 15 | "unit_or_t2": { 16 | "$ref": "#/definitions/Or_for_Null_and_int32" 17 | }, 18 | "s": { 19 | "$ref": "#/definitions/Str" 20 | }, 21 | "fake_map": { 22 | "type": "object", 23 | "additionalProperties": { 24 | "type": "array", 25 | "items": { 26 | "type": "string" 27 | }, 28 | "uniqueItems": true 29 | } 30 | } 31 | }, 32 | "definitions": { 33 | "Or_for_uint8_and_Boolean": { 34 | "anyOf": [ 35 | { 36 | "type": "integer", 37 | "format": "uint8", 38 | "minimum": 0.0 39 | }, 40 | { 41 | "type": "boolean" 42 | } 43 | ] 44 | }, 45 | "Or_for_Null_and_int32": { 46 | "anyOf": [ 47 | { 48 | "type": "null" 49 | }, 50 | { 51 | "type": "integer", 52 | "format": "int32" 53 | } 54 | ] 55 | }, 56 | "Str": { 57 | "type": "string" 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/atomic.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::sync::atomic::*; 5 | 6 | forward_impl!(AtomicBool => bool); 7 | 8 | forward_impl!(AtomicI8 => i8); 9 | forward_impl!(AtomicI16 => i16); 10 | forward_impl!(AtomicI32 => i32); 11 | #[cfg(std_atomic64)] 12 | forward_impl!(AtomicI64 => i64); 13 | forward_impl!(AtomicIsize => isize); 14 | 15 | forward_impl!(AtomicU8 => u8); 16 | forward_impl!(AtomicU16 => u16); 17 | forward_impl!(AtomicU32 => u32); 18 | #[cfg(std_atomic64)] 19 | forward_impl!(AtomicU64 => u64); 20 | forward_impl!(AtomicUsize => usize); 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use super::*; 25 | use crate::tests::schema_object_for; 26 | use pretty_assertions::assert_eq; 27 | 28 | #[test] 29 | fn schema_for_atomics() { 30 | let atomic_schema = schema_object_for::<( 31 | AtomicBool, 32 | AtomicI8, 33 | AtomicI16, 34 | AtomicI32, 35 | AtomicI64, 36 | AtomicIsize, 37 | AtomicU8, 38 | AtomicU16, 39 | AtomicU32, 40 | AtomicU64, 41 | AtomicUsize, 42 | )>(); 43 | let basic_schema = 44 | schema_object_for::<(bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize)>(); 45 | assert_eq!(atomic_schema, basic_schema); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/nonzero_signed.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | use std::num::*; 6 | 7 | macro_rules! nonzero_unsigned_impl { 8 | ($type:ty => $primitive:ty) => { 9 | impl JsonSchema for $type { 10 | no_ref_schema!(); 11 | 12 | fn schema_name() -> String { 13 | stringify!($type).to_owned() 14 | } 15 | 16 | fn schema_id() -> Cow<'static, str> { 17 | Cow::Borrowed(stringify!(std::num::$type)) 18 | } 19 | 20 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 21 | let zero_schema: Schema = SchemaObject { 22 | const_value: Some(0.into()), 23 | ..Default::default() 24 | } 25 | .into(); 26 | let mut schema: SchemaObject = <$primitive>::json_schema(generator).into(); 27 | schema.subschemas().not = Some(Box::from(zero_schema)); 28 | schema.into() 29 | } 30 | } 31 | }; 32 | } 33 | 34 | nonzero_unsigned_impl!(NonZeroI8 => i8); 35 | nonzero_unsigned_impl!(NonZeroI16 => i16); 36 | nonzero_unsigned_impl!(NonZeroI32 => i32); 37 | nonzero_unsigned_impl!(NonZeroI64 => i64); 38 | nonzero_unsigned_impl!(NonZeroI128 => i128); 39 | nonzero_unsigned_impl!(NonZeroIsize => isize); 40 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema_settings-openapi3.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", 3 | "title": "Outer", 4 | "type": "object", 5 | "required": [ 6 | "int", 7 | "value", 8 | "values" 9 | ], 10 | "properties": { 11 | "int": { 12 | "type": "integer", 13 | "format": "int32", 14 | "example": 8 15 | }, 16 | "values": { 17 | "type": "object", 18 | "additionalProperties": true 19 | }, 20 | "value": {}, 21 | "inner": { 22 | "allOf": [ 23 | { 24 | "$ref": "#/components/schemas/Inner" 25 | } 26 | ], 27 | "nullable": true 28 | } 29 | }, 30 | "definitions": { 31 | "Inner": { 32 | "oneOf": [ 33 | { 34 | "type": "string", 35 | "enum": [ 36 | "UndocumentedUnit1", 37 | "UndocumentedUnit2" 38 | ] 39 | }, 40 | { 41 | "description": "This is a documented unit variant", 42 | "type": "string", 43 | "enum": [ 44 | "DocumentedUnit" 45 | ] 46 | }, 47 | { 48 | "type": "object", 49 | "required": [ 50 | "ValueNewType" 51 | ], 52 | "properties": { 53 | "ValueNewType": {} 54 | }, 55 | "additionalProperties": false 56 | } 57 | ] 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /schemars/tests/expected/inline-subschemas-recursive.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "RecursiveOuter", 4 | "type": "object", 5 | "properties": { 6 | "direct": { 7 | "anyOf": [ 8 | { 9 | "$ref": "#/definitions/RecursiveOuter" 10 | }, 11 | { 12 | "type": "null" 13 | } 14 | ] 15 | }, 16 | "indirect": { 17 | "type": [ 18 | "object", 19 | "null" 20 | ], 21 | "required": [ 22 | "recursive" 23 | ], 24 | "properties": { 25 | "recursive": { 26 | "$ref": "#/definitions/RecursiveOuter" 27 | } 28 | } 29 | } 30 | }, 31 | "definitions": { 32 | "RecursiveOuter": { 33 | "type": "object", 34 | "properties": { 35 | "direct": { 36 | "anyOf": [ 37 | { 38 | "$ref": "#/definitions/RecursiveOuter" 39 | }, 40 | { 41 | "type": "null" 42 | } 43 | ] 44 | }, 45 | "indirect": { 46 | "type": [ 47 | "object", 48 | "null" 49 | ], 50 | "required": [ 51 | "recursive" 52 | ], 53 | "properties": { 54 | "recursive": { 55 | "$ref": "#/definitions/RecursiveOuter" 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /schemars/tests/expected/schema_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Outer", 4 | "type": "object", 5 | "required": [ 6 | "int", 7 | "value", 8 | "values" 9 | ], 10 | "properties": { 11 | "int": { 12 | "examples": [ 13 | 8, 14 | null 15 | ], 16 | "type": "integer", 17 | "format": "int32" 18 | }, 19 | "values": { 20 | "type": "object", 21 | "additionalProperties": true 22 | }, 23 | "value": true, 24 | "inner": { 25 | "anyOf": [ 26 | { 27 | "$ref": "#/definitions/Inner" 28 | }, 29 | { 30 | "type": "null" 31 | } 32 | ] 33 | } 34 | }, 35 | "definitions": { 36 | "Inner": { 37 | "oneOf": [ 38 | { 39 | "type": "string", 40 | "enum": [ 41 | "UndocumentedUnit1", 42 | "UndocumentedUnit2" 43 | ] 44 | }, 45 | { 46 | "description": "This is a documented unit variant", 47 | "type": "string", 48 | "enum": [ 49 | "DocumentedUnit" 50 | ] 51 | }, 52 | { 53 | "type": "object", 54 | "required": [ 55 | "ValueNewType" 56 | ], 57 | "properties": { 58 | "ValueNewType": true 59 | }, 60 | "additionalProperties": false 61 | } 62 | ] 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /schemars/tests/expected/schema_settings-2019_09.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "title": "Outer", 4 | "type": "object", 5 | "required": [ 6 | "int", 7 | "value", 8 | "values" 9 | ], 10 | "properties": { 11 | "int": { 12 | "examples": [ 13 | 8, 14 | null 15 | ], 16 | "type": "integer", 17 | "format": "int32" 18 | }, 19 | "values": { 20 | "type": "object", 21 | "additionalProperties": true 22 | }, 23 | "value": true, 24 | "inner": { 25 | "anyOf": [ 26 | { 27 | "$ref": "#/definitions/Inner" 28 | }, 29 | { 30 | "type": "null" 31 | } 32 | ] 33 | } 34 | }, 35 | "definitions": { 36 | "Inner": { 37 | "oneOf": [ 38 | { 39 | "type": "string", 40 | "enum": [ 41 | "UndocumentedUnit1", 42 | "UndocumentedUnit2" 43 | ] 44 | }, 45 | { 46 | "description": "This is a documented unit variant", 47 | "type": "string", 48 | "enum": [ 49 | "DocumentedUnit" 50 | ] 51 | }, 52 | { 53 | "type": "object", 54 | "required": [ 55 | "ValueNewType" 56 | ], 57 | "properties": { 58 | "ValueNewType": true 59 | }, 60 | "additionalProperties": false 61 | } 62 | ] 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /schemars/examples/remote_derive.rs: -------------------------------------------------------------------------------- 1 | // Pretend that this is somebody else's crate, not a module. 2 | mod other_crate { 3 | // Neither Schemars nor the other crate provides a JsonSchema impl 4 | // for this struct. 5 | pub struct Duration { 6 | pub secs: i64, 7 | pub nanos: i32, 8 | } 9 | } 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | use other_crate::Duration; 14 | use schemars::{schema_for, JsonSchema}; 15 | 16 | // This is just a copy of the remote data structure that Schemars can use to 17 | // create a suitable JsonSchema impl. 18 | #[derive(JsonSchema)] 19 | #[serde(remote = "Duration")] 20 | pub struct DurationDef { 21 | pub secs: i64, 22 | pub nanos: i32, 23 | } 24 | 25 | // Now the remote type can be used almost like it had its own JsonSchema impl 26 | // all along. The `with` attribute gives the path to the definition for the 27 | // remote type. Note that the real type of the field is the remote type, not 28 | // the definition type. 29 | #[derive(JsonSchema)] 30 | pub struct Process { 31 | pub command_line: String, 32 | #[serde(with = "DurationDef")] 33 | pub wall_time: Duration, 34 | // Generic types must be explicitly specified with turbofix `::<>` syntax. 35 | #[serde(with = "Vec::")] 36 | pub durations: Vec, 37 | } 38 | 39 | fn main() { 40 | let schema = schema_for!(Process); 41 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 42 | } 43 | -------------------------------------------------------------------------------- /schemars/tests/default.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | fn is_default(value: &T) -> bool { 6 | value == &T::default() 7 | } 8 | 9 | fn ten_and_true() -> MyStruct2 { 10 | MyStruct2 { 11 | my_int: 10, 12 | my_bool: true, 13 | } 14 | } 15 | 16 | fn six() -> i32 { 17 | 6 18 | } 19 | 20 | fn custom_serialize(value: &MyStruct2, ser: S) -> Result 21 | where 22 | S: serde::Serializer, 23 | { 24 | ser.collect_str(&format_args!("i:{} b:{}", value.my_int, value.my_bool)) 25 | } 26 | 27 | #[allow(dead_code)] 28 | #[derive(Default, JsonSchema)] 29 | #[serde(default)] 30 | struct MyStruct { 31 | my_int: i32, 32 | my_bool: bool, 33 | my_optional_string: Option, 34 | #[serde(serialize_with = "custom_serialize")] 35 | my_struct2: MyStruct2, 36 | #[serde( 37 | serialize_with = "custom_serialize", 38 | skip_serializing_if = "is_default" 39 | )] 40 | my_struct2_default_skipped: MyStruct2, 41 | not_serialize: NotSerialize, 42 | } 43 | 44 | #[allow(dead_code)] 45 | #[derive(Default, JsonSchema, PartialEq)] 46 | #[serde(default = "ten_and_true")] 47 | struct MyStruct2 { 48 | #[serde(default = "six")] 49 | my_int: i32, 50 | my_bool: bool, 51 | } 52 | 53 | #[derive(Default, JsonSchema)] 54 | struct NotSerialize; 55 | 56 | #[test] 57 | fn schema_default_values() -> TestResult { 58 | test_default_generated_schema::("default") 59 | } 60 | -------------------------------------------------------------------------------- /docs/_includes/examples/remote_derive.rs: -------------------------------------------------------------------------------- 1 | // Pretend that this is somebody else's crate, not a module. 2 | mod other_crate { 3 | // Neither Schemars nor the other crate provides a JsonSchema impl 4 | // for this struct. 5 | pub struct Duration { 6 | pub secs: i64, 7 | pub nanos: i32, 8 | } 9 | } 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | use other_crate::Duration; 14 | use schemars::{schema_for, JsonSchema}; 15 | 16 | // This is just a copy of the remote data structure that Schemars can use to 17 | // create a suitable JsonSchema impl. 18 | #[derive(JsonSchema)] 19 | #[serde(remote = "Duration")] 20 | pub struct DurationDef { 21 | pub secs: i64, 22 | pub nanos: i32, 23 | } 24 | 25 | // Now the remote type can be used almost like it had its own JsonSchema impl 26 | // all along. The `with` attribute gives the path to the definition for the 27 | // remote type. Note that the real type of the field is the remote type, not 28 | // the definition type. 29 | #[derive(JsonSchema)] 30 | pub struct Process { 31 | pub command_line: String, 32 | #[serde(with = "DurationDef")] 33 | pub wall_time: Duration, 34 | // Generic types must be explicitly specified with turbofix `::<>` syntax. 35 | #[serde(with = "Vec::")] 36 | pub durations: Vec, 37 | } 38 | 39 | fn main() { 40 | let schema = schema_for!(Process); 41 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 42 | } 43 | -------------------------------------------------------------------------------- /schemars/examples/schemars_attrs.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "myBool", 7 | "myNumber", 8 | "myVecStr" 9 | ], 10 | "properties": { 11 | "myBool": { 12 | "type": "boolean" 13 | }, 14 | "myNullableEnum": { 15 | "default": null, 16 | "anyOf": [ 17 | { 18 | "$ref": "#/definitions/MyEnum" 19 | }, 20 | { 21 | "type": "null" 22 | } 23 | ] 24 | }, 25 | "myNumber": { 26 | "type": "integer", 27 | "format": "int32", 28 | "maximum": 10.0, 29 | "minimum": 1.0 30 | }, 31 | "myVecStr": { 32 | "type": "array", 33 | "items": { 34 | "type": "string", 35 | "pattern": "^x$" 36 | } 37 | } 38 | }, 39 | "additionalProperties": false, 40 | "definitions": { 41 | "MyEnum": { 42 | "anyOf": [ 43 | { 44 | "type": "string", 45 | "format": "phone" 46 | }, 47 | { 48 | "type": "object", 49 | "required": [ 50 | "floats" 51 | ], 52 | "properties": { 53 | "floats": { 54 | "type": "array", 55 | "items": { 56 | "type": "number", 57 | "format": "float" 58 | }, 59 | "maxItems": 100, 60 | "minItems": 1 61 | } 62 | } 63 | } 64 | ] 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /docs/_includes/examples/schemars_attrs.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "myBool", 7 | "myNumber", 8 | "myVecStr" 9 | ], 10 | "properties": { 11 | "myBool": { 12 | "type": "boolean" 13 | }, 14 | "myNullableEnum": { 15 | "default": null, 16 | "anyOf": [ 17 | { 18 | "$ref": "#/definitions/MyEnum" 19 | }, 20 | { 21 | "type": "null" 22 | } 23 | ] 24 | }, 25 | "myNumber": { 26 | "type": "integer", 27 | "format": "int32", 28 | "maximum": 10.0, 29 | "minimum": 1.0 30 | }, 31 | "myVecStr": { 32 | "type": "array", 33 | "items": { 34 | "type": "string", 35 | "pattern": "^x$" 36 | } 37 | } 38 | }, 39 | "additionalProperties": false, 40 | "definitions": { 41 | "MyEnum": { 42 | "anyOf": [ 43 | { 44 | "type": "string", 45 | "format": "phone" 46 | }, 47 | { 48 | "type": "object", 49 | "required": [ 50 | "floats" 51 | ], 52 | "properties": { 53 | "floats": { 54 | "type": "array", 55 | "items": { 56 | "type": "number", 57 | "format": "float" 58 | }, 59 | "maxItems": 100, 60 | "minItems": 1 61 | } 62 | } 63 | } 64 | ] 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/ffi.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | use std::ffi::{CStr, CString, OsStr, OsString}; 6 | 7 | impl JsonSchema for OsString { 8 | fn schema_name() -> String { 9 | "OsString".to_owned() 10 | } 11 | 12 | fn schema_id() -> Cow<'static, str> { 13 | Cow::Borrowed("std::ffi::OsString") 14 | } 15 | 16 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 17 | let mut unix_schema = SchemaObject { 18 | instance_type: Some(InstanceType::Object.into()), 19 | ..Default::default() 20 | }; 21 | let obj = unix_schema.object(); 22 | obj.required.insert("Unix".to_owned()); 23 | obj.properties 24 | .insert("Unix".to_owned(), >::json_schema(generator)); 25 | 26 | let mut win_schema = SchemaObject { 27 | instance_type: Some(InstanceType::Object.into()), 28 | ..Default::default() 29 | }; 30 | let obj = win_schema.object(); 31 | obj.required.insert("Windows".to_owned()); 32 | obj.properties 33 | .insert("Windows".to_owned(), >::json_schema(generator)); 34 | 35 | let mut schema = SchemaObject::default(); 36 | schema.subschemas().one_of = Some(vec![unix_schema.into(), win_schema.into()]); 37 | schema.into() 38 | } 39 | } 40 | 41 | forward_impl!(OsStr => OsString); 42 | 43 | forward_impl!(CString => Vec); 44 | forward_impl!(CStr => Vec); 45 | -------------------------------------------------------------------------------- /schemars/tests/util/mod.rs: -------------------------------------------------------------------------------- 1 | use pretty_assertions::assert_eq; 2 | use schemars::{r#gen::SchemaSettings, schema::RootSchema, schema_for, JsonSchema}; 3 | use std::error::Error; 4 | use std::fs; 5 | 6 | pub type TestResult = Result<(), Box>; 7 | 8 | #[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379 9 | pub fn test_generated_schema(file: &str, settings: SchemaSettings) -> TestResult { 10 | let actual = settings.into_generator().into_root_schema_for::(); 11 | test_schema(&actual, file) 12 | } 13 | 14 | #[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379 15 | pub fn test_default_generated_schema(file: &str) -> TestResult { 16 | let actual = schema_for!(T); 17 | test_schema(&actual, file) 18 | } 19 | 20 | pub fn test_schema(actual: &RootSchema, file: &str) -> TestResult { 21 | let expected_json = match fs::read_to_string(format!("tests/expected/{}.json", file)) { 22 | Ok(j) => j, 23 | Err(e) => { 24 | write_actual_to_file(actual, file)?; 25 | return Err(Box::from(e)); 26 | } 27 | }; 28 | let expected = &serde_json::from_str(&expected_json)?; 29 | 30 | if actual != expected { 31 | write_actual_to_file(actual, file)?; 32 | } 33 | 34 | assert_eq!(expected, actual); 35 | Ok(()) 36 | } 37 | 38 | fn write_actual_to_file(schema: &RootSchema, file: &str) -> TestResult { 39 | let actual_json = serde_json::to_string_pretty(&schema)?; 40 | fs::write(format!("tests/actual/{}.json", file), actual_json)?; 41 | Ok(()) 42 | } 43 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema-name-mixed-generics.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MixedGenericStruct_for_MyStruct_for_int32_and_Null_and_Boolean_and_Array_of_String_and_42_and_z", 4 | "type": "object", 5 | "required": [ 6 | "foo", 7 | "generic" 8 | ], 9 | "properties": { 10 | "foo": { 11 | "type": "integer", 12 | "format": "int32" 13 | }, 14 | "generic": { 15 | "$ref": "#/definitions/MyStruct_for_int32_and_Null_and_Boolean_and_Array_of_String" 16 | } 17 | }, 18 | "definitions": { 19 | "MySimpleStruct": { 20 | "type": "object", 21 | "required": [ 22 | "foo" 23 | ], 24 | "properties": { 25 | "foo": { 26 | "type": "integer", 27 | "format": "int32" 28 | } 29 | } 30 | }, 31 | "MyStruct_for_int32_and_Null_and_Boolean_and_Array_of_String": { 32 | "type": "object", 33 | "required": [ 34 | "inner", 35 | "t", 36 | "u", 37 | "v", 38 | "w" 39 | ], 40 | "properties": { 41 | "inner": { 42 | "$ref": "#/definitions/MySimpleStruct" 43 | }, 44 | "t": { 45 | "type": "integer", 46 | "format": "int32" 47 | }, 48 | "u": { 49 | "type": "null" 50 | }, 51 | "v": { 52 | "type": "boolean" 53 | }, 54 | "w": { 55 | "type": "array", 56 | "items": { 57 | "type": "string" 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /schemars/tests/expected/enum-untagged.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Untagged", 4 | "anyOf": [ 5 | { 6 | "type": "null" 7 | }, 8 | { 9 | "type": "object", 10 | "additionalProperties": { 11 | "type": "string" 12 | } 13 | }, 14 | { 15 | "$ref": "#/definitions/UnitStruct" 16 | }, 17 | { 18 | "$ref": "#/definitions/Struct" 19 | }, 20 | { 21 | "type": "object", 22 | "required": [ 23 | "bar", 24 | "foo" 25 | ], 26 | "properties": { 27 | "foo": { 28 | "type": "integer", 29 | "format": "int32" 30 | }, 31 | "bar": { 32 | "type": "boolean" 33 | } 34 | } 35 | }, 36 | { 37 | "type": "array", 38 | "items": [ 39 | { 40 | "type": "integer", 41 | "format": "int32" 42 | }, 43 | { 44 | "type": "boolean" 45 | } 46 | ], 47 | "maxItems": 2, 48 | "minItems": 2 49 | }, 50 | { 51 | "type": "integer", 52 | "format": "int32" 53 | } 54 | ], 55 | "definitions": { 56 | "UnitStruct": { 57 | "type": "null" 58 | }, 59 | "Struct": { 60 | "type": "object", 61 | "required": [ 62 | "bar", 63 | "foo" 64 | ], 65 | "properties": { 66 | "foo": { 67 | "type": "integer", 68 | "format": "int32" 69 | }, 70 | "bar": { 71 | "type": "boolean" 72 | } 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /schemars/tests/macro.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | macro_rules! build_struct { 6 | ( 7 | $id:ident { $($t:tt)* } 8 | ) => { 9 | #[allow(dead_code)] 10 | #[derive(JsonSchema)] 11 | pub struct $id { 12 | x: u8, 13 | $($t)* 14 | } 15 | }; 16 | } 17 | 18 | build_struct!(A { v: i32 }); 19 | 20 | #[test] 21 | fn macro_built_struct() -> TestResult { 22 | test_default_generated_schema::("macro_built_struct") 23 | } 24 | 25 | macro_rules! build_enum { 26 | ( 27 | $(#[$outer_derive:meta])* 28 | $outer:ident { 29 | $($(#[$inner_derive:meta])* 30 | $inner:ident { 31 | $( $(#[$field_attribute:meta])* 32 | $field:ident : $ty:ty),* 33 | })* 34 | } 35 | ) => { 36 | 37 | $( 38 | $(#[$inner_derive])* 39 | pub struct $inner { 40 | $( 41 | $(#[$field_attribute])* 42 | pub $field: $ty 43 | ),* 44 | } 45 | )* 46 | 47 | $(#[$outer_derive])* 48 | pub enum $outer { 49 | $( 50 | $inner($inner) 51 | ),* 52 | } 53 | } 54 | } 55 | 56 | build_enum!( 57 | #[derive(JsonSchema)] 58 | OuterEnum { 59 | #[derive(JsonSchema)] 60 | InnerStruct { 61 | x: i32 62 | } 63 | } 64 | 65 | ); 66 | 67 | #[test] 68 | fn macro_built_enum() -> TestResult { 69 | test_default_generated_schema::("macro_built_enum") 70 | } 71 | -------------------------------------------------------------------------------- /schemars/tests/expected/enum-untagged-duf.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Untagged", 4 | "anyOf": [ 5 | { 6 | "type": "null" 7 | }, 8 | { 9 | "type": "object", 10 | "additionalProperties": { 11 | "type": "string" 12 | } 13 | }, 14 | { 15 | "$ref": "#/definitions/UnitStruct" 16 | }, 17 | { 18 | "$ref": "#/definitions/Struct" 19 | }, 20 | { 21 | "type": "object", 22 | "required": [ 23 | "bar", 24 | "foo" 25 | ], 26 | "properties": { 27 | "foo": { 28 | "type": "integer", 29 | "format": "int32" 30 | }, 31 | "bar": { 32 | "type": "boolean" 33 | } 34 | }, 35 | "additionalProperties": false 36 | }, 37 | { 38 | "type": "array", 39 | "items": [ 40 | { 41 | "type": "integer", 42 | "format": "int32" 43 | }, 44 | { 45 | "type": "boolean" 46 | } 47 | ], 48 | "maxItems": 2, 49 | "minItems": 2 50 | }, 51 | { 52 | "type": "integer", 53 | "format": "int32" 54 | } 55 | ], 56 | "definitions": { 57 | "UnitStruct": { 58 | "type": "null" 59 | }, 60 | "Struct": { 61 | "type": "object", 62 | "required": [ 63 | "bar", 64 | "foo" 65 | ], 66 | "properties": { 67 | "foo": { 68 | "type": "integer", 69 | "format": "int32" 70 | }, 71 | "bar": { 72 | "type": "boolean" 73 | } 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /schemars/tests/schema_with_struct.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | fn schema_fn(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { 6 | ::json_schema(generator) 7 | } 8 | 9 | struct DoesntImplementJsonSchema; 10 | 11 | #[allow(dead_code)] 12 | #[derive(JsonSchema)] 13 | struct Struct { 14 | #[schemars(schema_with = "schema_fn")] 15 | foo: DoesntImplementJsonSchema, 16 | bar: i32, 17 | #[schemars(schema_with = "schema_fn")] 18 | baz: DoesntImplementJsonSchema, 19 | } 20 | 21 | #[test] 22 | fn struct_normal() -> TestResult { 23 | test_default_generated_schema::("schema_with-struct") 24 | } 25 | 26 | #[allow(dead_code)] 27 | #[derive(JsonSchema)] 28 | pub struct Tuple( 29 | #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, 30 | i32, 31 | #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, 32 | ); 33 | 34 | #[test] 35 | fn struct_tuple() -> TestResult { 36 | test_default_generated_schema::("schema_with-tuple") 37 | } 38 | 39 | #[derive(JsonSchema)] 40 | pub struct Newtype(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema); 41 | 42 | #[test] 43 | fn struct_newtype() -> TestResult { 44 | test_default_generated_schema::("schema_with-newtype") 45 | } 46 | 47 | #[derive(JsonSchema)] 48 | #[schemars(transparent)] 49 | pub struct TransparentNewtype(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema); 50 | 51 | #[test] 52 | fn struct_transparent_newtype() -> TestResult { 53 | test_default_generated_schema::("schema_with-transparent-newtype") 54 | } 55 | -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-enum-external.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "External", 4 | "oneOf": [ 5 | { 6 | "type": "object", 7 | "required": [ 8 | "struct" 9 | ], 10 | "properties": { 11 | "struct": { 12 | "type": "object", 13 | "required": [ 14 | "foo" 15 | ], 16 | "properties": { 17 | "foo": { 18 | "type": "boolean" 19 | } 20 | } 21 | } 22 | }, 23 | "additionalProperties": false 24 | }, 25 | { 26 | "type": "object", 27 | "required": [ 28 | "newType" 29 | ], 30 | "properties": { 31 | "newType": { 32 | "type": "boolean" 33 | } 34 | }, 35 | "additionalProperties": false 36 | }, 37 | { 38 | "type": "object", 39 | "required": [ 40 | "tuple" 41 | ], 42 | "properties": { 43 | "tuple": { 44 | "type": "array", 45 | "items": [ 46 | { 47 | "type": "boolean" 48 | }, 49 | { 50 | "type": "integer", 51 | "format": "int32" 52 | } 53 | ], 54 | "maxItems": 2, 55 | "minItems": 2 56 | } 57 | }, 58 | "additionalProperties": false 59 | }, 60 | { 61 | "type": "object", 62 | "required": [ 63 | "unit" 64 | ], 65 | "properties": { 66 | "unit": { 67 | "type": "boolean" 68 | } 69 | }, 70 | "additionalProperties": false 71 | } 72 | ] 73 | } -------------------------------------------------------------------------------- /schemars/examples/validate.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "my_bool", 7 | "my_int", 8 | "my_nullable_enum" 9 | ], 10 | "properties": { 11 | "my_bool": { 12 | "type": "boolean" 13 | }, 14 | "my_int": { 15 | "type": "integer", 16 | "format": "int32", 17 | "maximum": 10.0, 18 | "minimum": 1.0 19 | }, 20 | "my_nullable_enum": { 21 | "oneOf": [ 22 | { 23 | "type": "object", 24 | "required": [ 25 | "StringNewType" 26 | ], 27 | "properties": { 28 | "StringNewType": { 29 | "type": "string", 30 | "format": "phone" 31 | } 32 | }, 33 | "additionalProperties": false 34 | }, 35 | { 36 | "type": "object", 37 | "required": [ 38 | "StructVariant" 39 | ], 40 | "properties": { 41 | "StructVariant": { 42 | "type": "object", 43 | "required": [ 44 | "floats" 45 | ], 46 | "properties": { 47 | "floats": { 48 | "type": "array", 49 | "items": { 50 | "type": "number", 51 | "format": "float" 52 | }, 53 | "maxItems": 100, 54 | "minItems": 1 55 | } 56 | } 57 | } 58 | }, 59 | "additionalProperties": false 60 | } 61 | ] 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /docs/_includes/examples/validate.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "my_bool", 7 | "my_int", 8 | "my_nullable_enum" 9 | ], 10 | "properties": { 11 | "my_bool": { 12 | "type": "boolean" 13 | }, 14 | "my_int": { 15 | "type": "integer", 16 | "format": "int32", 17 | "maximum": 10.0, 18 | "minimum": 1.0 19 | }, 20 | "my_nullable_enum": { 21 | "oneOf": [ 22 | { 23 | "type": "object", 24 | "required": [ 25 | "StringNewType" 26 | ], 27 | "properties": { 28 | "StringNewType": { 29 | "type": "string", 30 | "format": "phone" 31 | } 32 | }, 33 | "additionalProperties": false 34 | }, 35 | { 36 | "type": "object", 37 | "required": [ 38 | "StructVariant" 39 | ], 40 | "properties": { 41 | "StructVariant": { 42 | "type": "object", 43 | "required": [ 44 | "floats" 45 | ], 46 | "properties": { 47 | "floats": { 48 | "type": "array", 49 | "items": { 50 | "type": "number", 51 | "format": "float" 52 | }, 53 | "maxItems": 100, 54 | "minItems": 1 55 | } 56 | } 57 | } 58 | }, 59 | "additionalProperties": false 60 | } 61 | ] 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /schemars/examples/custom_settings.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "my_bool", 7 | "my_int" 8 | ], 9 | "properties": { 10 | "my_bool": { 11 | "type": "boolean" 12 | }, 13 | "my_int": { 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "my_nullable_enum": { 18 | "allOf": [ 19 | { 20 | "$ref": "#/definitions/MyEnum" 21 | } 22 | ], 23 | "nullable": true 24 | } 25 | }, 26 | "definitions": { 27 | "MyEnum": { 28 | "oneOf": [ 29 | { 30 | "type": "object", 31 | "required": [ 32 | "StringNewType" 33 | ], 34 | "properties": { 35 | "StringNewType": { 36 | "type": "string" 37 | } 38 | }, 39 | "additionalProperties": false 40 | }, 41 | { 42 | "type": "object", 43 | "required": [ 44 | "StructVariant" 45 | ], 46 | "properties": { 47 | "StructVariant": { 48 | "type": "object", 49 | "required": [ 50 | "floats" 51 | ], 52 | "properties": { 53 | "floats": { 54 | "type": "array", 55 | "items": { 56 | "type": "number", 57 | "format": "float" 58 | } 59 | } 60 | } 61 | } 62 | }, 63 | "additionalProperties": false 64 | } 65 | ] 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /docs/_includes/examples/custom_settings.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "my_bool", 7 | "my_int" 8 | ], 9 | "properties": { 10 | "my_bool": { 11 | "type": "boolean" 12 | }, 13 | "my_int": { 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "my_nullable_enum": { 18 | "allOf": [ 19 | { 20 | "$ref": "#/definitions/MyEnum" 21 | } 22 | ], 23 | "nullable": true 24 | } 25 | }, 26 | "definitions": { 27 | "MyEnum": { 28 | "oneOf": [ 29 | { 30 | "type": "object", 31 | "required": [ 32 | "StringNewType" 33 | ], 34 | "properties": { 35 | "StringNewType": { 36 | "type": "string" 37 | } 38 | }, 39 | "additionalProperties": false 40 | }, 41 | { 42 | "type": "object", 43 | "required": [ 44 | "StructVariant" 45 | ], 46 | "properties": { 47 | "StructVariant": { 48 | "type": "object", 49 | "required": [ 50 | "floats" 51 | ], 52 | "properties": { 53 | "floats": { 54 | "type": "array", 55 | "items": { 56 | "type": "number", 57 | "format": "float" 58 | } 59 | } 60 | } 61 | } 62 | }, 63 | "additionalProperties": false 64 | } 65 | ] 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/nonzero_unsigned.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | use std::num::*; 6 | 7 | macro_rules! nonzero_unsigned_impl { 8 | ($type:ty => $primitive:ty) => { 9 | impl JsonSchema for $type { 10 | no_ref_schema!(); 11 | 12 | fn schema_name() -> String { 13 | stringify!($type).to_owned() 14 | } 15 | 16 | fn schema_id() -> Cow<'static, str> { 17 | Cow::Borrowed(stringify!(std::num::$type)) 18 | } 19 | 20 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 21 | let mut schema: SchemaObject = <$primitive>::json_schema(generator).into(); 22 | schema.number().minimum = Some(1.0); 23 | schema.into() 24 | } 25 | } 26 | }; 27 | } 28 | 29 | nonzero_unsigned_impl!(NonZeroU8 => u8); 30 | nonzero_unsigned_impl!(NonZeroU16 => u16); 31 | nonzero_unsigned_impl!(NonZeroU32 => u32); 32 | nonzero_unsigned_impl!(NonZeroU64 => u64); 33 | nonzero_unsigned_impl!(NonZeroU128 => u128); 34 | nonzero_unsigned_impl!(NonZeroUsize => usize); 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use super::*; 39 | use crate::tests::schema_object_for; 40 | use pretty_assertions::assert_eq; 41 | 42 | #[test] 43 | fn schema_for_nonzero_u32() { 44 | let schema = schema_object_for::(); 45 | assert_eq!(schema.number.unwrap().minimum, Some(1.0)); 46 | assert_eq!(schema.instance_type, Some(InstanceType::Integer.into())); 47 | assert_eq!(schema.format, Some("uint32".to_owned())); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /schemars/examples/main.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "my_bool", 7 | "my_int" 8 | ], 9 | "properties": { 10 | "my_bool": { 11 | "type": "boolean" 12 | }, 13 | "my_int": { 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "my_nullable_enum": { 18 | "anyOf": [ 19 | { 20 | "$ref": "#/definitions/MyEnum" 21 | }, 22 | { 23 | "type": "null" 24 | } 25 | ] 26 | } 27 | }, 28 | "definitions": { 29 | "MyEnum": { 30 | "oneOf": [ 31 | { 32 | "type": "object", 33 | "required": [ 34 | "StringNewType" 35 | ], 36 | "properties": { 37 | "StringNewType": { 38 | "type": "string" 39 | } 40 | }, 41 | "additionalProperties": false 42 | }, 43 | { 44 | "type": "object", 45 | "required": [ 46 | "StructVariant" 47 | ], 48 | "properties": { 49 | "StructVariant": { 50 | "type": "object", 51 | "required": [ 52 | "floats" 53 | ], 54 | "properties": { 55 | "floats": { 56 | "type": "array", 57 | "items": { 58 | "type": "number", 59 | "format": "float" 60 | } 61 | } 62 | } 63 | } 64 | }, 65 | "additionalProperties": false 66 | } 67 | ] 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /docs/_includes/examples/main.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "my_bool", 7 | "my_int" 8 | ], 9 | "properties": { 10 | "my_bool": { 11 | "type": "boolean" 12 | }, 13 | "my_int": { 14 | "type": "integer", 15 | "format": "int32" 16 | }, 17 | "my_nullable_enum": { 18 | "anyOf": [ 19 | { 20 | "$ref": "#/definitions/MyEnum" 21 | }, 22 | { 23 | "type": "null" 24 | } 25 | ] 26 | } 27 | }, 28 | "definitions": { 29 | "MyEnum": { 30 | "oneOf": [ 31 | { 32 | "type": "object", 33 | "required": [ 34 | "StringNewType" 35 | ], 36 | "properties": { 37 | "StringNewType": { 38 | "type": "string" 39 | } 40 | }, 41 | "additionalProperties": false 42 | }, 43 | { 44 | "type": "object", 45 | "required": [ 46 | "StructVariant" 47 | ], 48 | "properties": { 49 | "StructVariant": { 50 | "type": "object", 51 | "required": [ 52 | "floats" 53 | ], 54 | "properties": { 55 | "floats": { 56 | "type": "array", 57 | "items": { 58 | "type": "number", 59 | "format": "float" 60 | } 61 | } 62 | } 63 | } 64 | }, 65 | "additionalProperties": false 66 | } 67 | ] 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /schemars/tests/expected/validate_inner.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Struct", 4 | "type": "object", 5 | "required": [ 6 | "array_str_length", 7 | "slice_str_contains", 8 | "vec_i32_range", 9 | "vec_str_length", 10 | "vec_str_length2", 11 | "vec_str_regex", 12 | "vec_str_url" 13 | ], 14 | "properties": { 15 | "array_str_length": { 16 | "type": "array", 17 | "items": { 18 | "type": "string", 19 | "maxLength": 100, 20 | "minLength": 5 21 | }, 22 | "maxItems": 2, 23 | "minItems": 2 24 | }, 25 | "slice_str_contains": { 26 | "type": "array", 27 | "items": { 28 | "type": "string", 29 | "pattern": "substring\\.\\.\\." 30 | } 31 | }, 32 | "vec_i32_range": { 33 | "type": "array", 34 | "items": { 35 | "type": "integer", 36 | "format": "int32", 37 | "maximum": 10.0, 38 | "minimum": -10.0 39 | } 40 | }, 41 | "vec_str_length": { 42 | "type": "array", 43 | "items": { 44 | "type": "string", 45 | "maxLength": 100, 46 | "minLength": 1 47 | } 48 | }, 49 | "vec_str_length2": { 50 | "type": "array", 51 | "items": { 52 | "type": "string", 53 | "maxLength": 100, 54 | "minLength": 1 55 | }, 56 | "maxItems": 3, 57 | "minItems": 1 58 | }, 59 | "vec_str_regex": { 60 | "type": "array", 61 | "items": { 62 | "type": "string", 63 | "pattern": "^[Hh]ello\\b" 64 | } 65 | }, 66 | "vec_str_url": { 67 | "type": "array", 68 | "items": { 69 | "type": "string", 70 | "format": "uri" 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /schemars/tests/expected/from_value_draft07.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "examples": [ 5 | { 6 | "myBool": true, 7 | "myInnerStruct": { 8 | "my_empty_map": {}, 9 | "my_empty_vec": [], 10 | "my_map": { 11 | "": 0.0 12 | }, 13 | "my_tuple": [ 14 | "💩", 15 | 42 16 | ], 17 | "my_vec": [ 18 | "hello", 19 | "world" 20 | ] 21 | }, 22 | "myInt": 123, 23 | "myNullableEnum": null 24 | } 25 | ], 26 | "type": "object", 27 | "properties": { 28 | "myInt": { 29 | "type": "integer" 30 | }, 31 | "myBool": { 32 | "type": "boolean" 33 | }, 34 | "myNullableEnum": true, 35 | "myInnerStruct": { 36 | "type": "object", 37 | "properties": { 38 | "my_map": { 39 | "type": "object", 40 | "additionalProperties": { 41 | "type": "number" 42 | } 43 | }, 44 | "my_vec": { 45 | "type": "array", 46 | "items": { 47 | "type": "string" 48 | } 49 | }, 50 | "my_empty_map": { 51 | "type": "object", 52 | "additionalProperties": true 53 | }, 54 | "my_empty_vec": { 55 | "type": "array", 56 | "items": true 57 | }, 58 | "my_tuple": { 59 | "type": "array", 60 | "items": [ 61 | { 62 | "type": "string", 63 | "maxLength": 1, 64 | "minLength": 1 65 | }, 66 | { 67 | "type": "integer" 68 | } 69 | ], 70 | "maxItems": 2, 71 | "minItems": 2 72 | } 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /schemars/tests/expected/from_value_2019_09.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "title": "MyStruct", 4 | "examples": [ 5 | { 6 | "myBool": true, 7 | "myInnerStruct": { 8 | "my_empty_map": {}, 9 | "my_empty_vec": [], 10 | "my_map": { 11 | "": 0.0 12 | }, 13 | "my_tuple": [ 14 | "💩", 15 | 42 16 | ], 17 | "my_vec": [ 18 | "hello", 19 | "world" 20 | ] 21 | }, 22 | "myInt": 123, 23 | "myNullableEnum": null 24 | } 25 | ], 26 | "type": "object", 27 | "properties": { 28 | "myInt": { 29 | "type": "integer" 30 | }, 31 | "myBool": { 32 | "type": "boolean" 33 | }, 34 | "myNullableEnum": true, 35 | "myInnerStruct": { 36 | "type": "object", 37 | "properties": { 38 | "my_map": { 39 | "type": "object", 40 | "additionalProperties": { 41 | "type": "number" 42 | } 43 | }, 44 | "my_vec": { 45 | "type": "array", 46 | "items": { 47 | "type": "string" 48 | } 49 | }, 50 | "my_empty_map": { 51 | "type": "object", 52 | "additionalProperties": true 53 | }, 54 | "my_empty_vec": { 55 | "type": "array", 56 | "items": true 57 | }, 58 | "my_tuple": { 59 | "type": "array", 60 | "items": [ 61 | { 62 | "type": "string", 63 | "maxLength": 1, 64 | "minLength": 1 65 | }, 66 | { 67 | "type": "integer" 68 | } 69 | ], 70 | "maxItems": 2, 71 | "minItems": 2 72 | } 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /schemars/tests/expected/from_value_openapi3.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "properties": { 6 | "myInt": { 7 | "type": "integer" 8 | }, 9 | "myBool": { 10 | "type": "boolean" 11 | }, 12 | "myNullableEnum": { 13 | "nullable": true 14 | }, 15 | "myInnerStruct": { 16 | "type": "object", 17 | "properties": { 18 | "my_map": { 19 | "type": "object", 20 | "additionalProperties": { 21 | "type": "number" 22 | } 23 | }, 24 | "my_vec": { 25 | "type": "array", 26 | "items": { 27 | "type": "string" 28 | } 29 | }, 30 | "my_empty_map": { 31 | "type": "object", 32 | "additionalProperties": true 33 | }, 34 | "my_empty_vec": { 35 | "type": "array", 36 | "items": {} 37 | }, 38 | "my_tuple": { 39 | "type": "array", 40 | "items": [ 41 | { 42 | "type": "string", 43 | "maxLength": 1, 44 | "minLength": 1 45 | }, 46 | { 47 | "type": "integer" 48 | } 49 | ], 50 | "maxItems": 2, 51 | "minItems": 2 52 | } 53 | } 54 | } 55 | }, 56 | "example": { 57 | "myBool": true, 58 | "myInnerStruct": { 59 | "my_empty_map": {}, 60 | "my_empty_vec": [], 61 | "my_map": { 62 | "": 0.0 63 | }, 64 | "my_tuple": [ 65 | "💩", 66 | 42 67 | ], 68 | "my_vec": [ 69 | "hello", 70 | "world" 71 | ] 72 | }, 73 | "myInt": 123, 74 | "myNullableEnum": null 75 | } 76 | } -------------------------------------------------------------------------------- /schemars/examples/custom_serialization.rs: -------------------------------------------------------------------------------- 1 | use schemars::schema::{Schema, SchemaObject}; 2 | use schemars::{r#gen::SchemaGenerator, schema_for, JsonSchema}; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | // `int_as_string` and `bool_as_string` use the schema for `String`. 6 | #[derive(Default, Deserialize, Serialize, JsonSchema)] 7 | pub struct MyStruct { 8 | #[serde(default = "eight", with = "as_string")] 9 | #[schemars(with = "String")] 10 | pub int_as_string: i32, 11 | 12 | #[serde(default = "eight")] 13 | pub int_normal: i32, 14 | 15 | #[serde(default, with = "as_string")] 16 | #[schemars(schema_with = "make_custom_schema")] 17 | pub bool_as_string: bool, 18 | 19 | #[serde(default)] 20 | pub bool_normal: bool, 21 | } 22 | 23 | fn make_custom_schema(generator: &mut SchemaGenerator) -> Schema { 24 | let mut schema: SchemaObject = ::json_schema(generator).into(); 25 | schema.format = Some("boolean".to_owned()); 26 | schema.into() 27 | } 28 | 29 | fn eight() -> i32 { 30 | 8 31 | } 32 | 33 | // This module serializes values as strings 34 | mod as_string { 35 | use serde::{de::Error, Deserialize, Deserializer, Serializer}; 36 | 37 | pub fn serialize(value: &T, serializer: S) -> Result 38 | where 39 | T: std::fmt::Display, 40 | S: Serializer, 41 | { 42 | serializer.collect_str(value) 43 | } 44 | 45 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result 46 | where 47 | T: std::str::FromStr, 48 | D: Deserializer<'de>, 49 | { 50 | let string = String::deserialize(deserializer)?; 51 | string 52 | .parse() 53 | .map_err(|_| D::Error::custom("Input was not valid")) 54 | } 55 | } 56 | 57 | fn main() { 58 | let schema = schema_for!(MyStruct); 59 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 60 | } 61 | -------------------------------------------------------------------------------- /docs/_includes/examples/custom_serialization.rs: -------------------------------------------------------------------------------- 1 | use schemars::schema::{Schema, SchemaObject}; 2 | use schemars::{r#gen::SchemaGenerator, schema_for, JsonSchema}; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | // `int_as_string` and `bool_as_string` use the schema for `String`. 6 | #[derive(Default, Deserialize, Serialize, JsonSchema)] 7 | pub struct MyStruct { 8 | #[serde(default = "eight", with = "as_string")] 9 | #[schemars(with = "String")] 10 | pub int_as_string: i32, 11 | 12 | #[serde(default = "eight")] 13 | pub int_normal: i32, 14 | 15 | #[serde(default, with = "as_string")] 16 | #[schemars(schema_with = "make_custom_schema")] 17 | pub bool_as_string: bool, 18 | 19 | #[serde(default)] 20 | pub bool_normal: bool, 21 | } 22 | 23 | fn make_custom_schema(generator: &mut SchemaGenerator) -> Schema { 24 | let mut schema: SchemaObject = ::json_schema(generator).into(); 25 | schema.format = Some("boolean".to_owned()); 26 | schema.into() 27 | } 28 | 29 | fn eight() -> i32 { 30 | 8 31 | } 32 | 33 | // This module serializes values as strings 34 | mod as_string { 35 | use serde::{de::Error, Deserialize, Deserializer, Serializer}; 36 | 37 | pub fn serialize(value: &T, serializer: S) -> Result 38 | where 39 | T: std::fmt::Display, 40 | S: Serializer, 41 | { 42 | serializer.collect_str(value) 43 | } 44 | 45 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result 46 | where 47 | T: std::str::FromStr, 48 | D: Deserializer<'de>, 49 | { 50 | let string = String::deserialize(deserializer)?; 51 | string 52 | .parse() 53 | .map_err(|_| D::Error::custom("Input was not valid")) 54 | } 55 | } 56 | 57 | fn main() { 58 | let schema = schema_for!(MyStruct); 59 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 60 | } 61 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/time.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use std::borrow::Cow; 5 | use std::time::{Duration, SystemTime}; 6 | 7 | impl JsonSchema for Duration { 8 | fn schema_name() -> String { 9 | "Duration".to_owned() 10 | } 11 | 12 | fn schema_id() -> Cow<'static, str> { 13 | Cow::Borrowed("std::time::Duration") 14 | } 15 | 16 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 17 | let mut schema = SchemaObject { 18 | instance_type: Some(InstanceType::Object.into()), 19 | ..Default::default() 20 | }; 21 | let obj = schema.object(); 22 | obj.required.insert("secs".to_owned()); 23 | obj.required.insert("nanos".to_owned()); 24 | obj.properties 25 | .insert("secs".to_owned(), ::json_schema(generator)); 26 | obj.properties 27 | .insert("nanos".to_owned(), ::json_schema(generator)); 28 | schema.into() 29 | } 30 | } 31 | 32 | impl JsonSchema for SystemTime { 33 | fn schema_name() -> String { 34 | "SystemTime".to_owned() 35 | } 36 | 37 | fn schema_id() -> Cow<'static, str> { 38 | Cow::Borrowed("std::time::SystemTime") 39 | } 40 | 41 | fn json_schema(generator: &mut SchemaGenerator) -> Schema { 42 | let mut schema = SchemaObject { 43 | instance_type: Some(InstanceType::Object.into()), 44 | ..Default::default() 45 | }; 46 | let obj = schema.object(); 47 | obj.required.insert("secs_since_epoch".to_owned()); 48 | obj.required.insert("nanos_since_epoch".to_owned()); 49 | obj.properties 50 | .insert("secs_since_epoch".to_owned(), ::json_schema(generator)); 51 | obj.properties.insert( 52 | "nanos_since_epoch".to_owned(), 53 | ::json_schema(generator), 54 | ); 55 | schema.into() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /schemars/tests/expected/result.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Container", 4 | "type": "object", 5 | "required": [ 6 | "result1", 7 | "result2" 8 | ], 9 | "properties": { 10 | "result1": { 11 | "$ref": "#/definitions/Result_of_MyStruct_or_Array_of_String" 12 | }, 13 | "result2": { 14 | "$ref": "#/definitions/Result_of_Boolean_or_Null" 15 | } 16 | }, 17 | "definitions": { 18 | "Result_of_MyStruct_or_Array_of_String": { 19 | "oneOf": [ 20 | { 21 | "type": "object", 22 | "required": [ 23 | "Ok" 24 | ], 25 | "properties": { 26 | "Ok": { 27 | "$ref": "#/definitions/MyStruct" 28 | } 29 | } 30 | }, 31 | { 32 | "type": "object", 33 | "required": [ 34 | "Err" 35 | ], 36 | "properties": { 37 | "Err": { 38 | "type": "array", 39 | "items": { 40 | "type": "string" 41 | } 42 | } 43 | } 44 | } 45 | ] 46 | }, 47 | "MyStruct": { 48 | "type": "object", 49 | "required": [ 50 | "foo" 51 | ], 52 | "properties": { 53 | "foo": { 54 | "type": "integer", 55 | "format": "int32" 56 | } 57 | } 58 | }, 59 | "Result_of_Boolean_or_Null": { 60 | "oneOf": [ 61 | { 62 | "type": "object", 63 | "required": [ 64 | "Ok" 65 | ], 66 | "properties": { 67 | "Ok": { 68 | "type": "boolean" 69 | } 70 | } 71 | }, 72 | { 73 | "type": "object", 74 | "required": [ 75 | "Err" 76 | ], 77 | "properties": { 78 | "Err": { 79 | "type": "null" 80 | } 81 | } 82 | } 83 | ] 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /docs/3-generating.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Generating Schemas 4 | nav_order: 4 5 | permalink: /generating/ 6 | --- 7 | 8 | # Generating Schemas 9 | 10 | 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: 11 | ```rust 12 | let my_schema = schema_for!(MyStruct); 13 | ``` 14 | 15 | 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. 16 | 17 | 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: 18 | * [`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). 19 | * [`SchemaGenerator`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaGenerator.html), which manages the generation of a schema document. 20 | 21 | See the API documentation for more info on how to use those types for custom schema generation. 22 | 23 | ## Schema from Example Value 24 | 25 | 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. 26 | 27 | ```rust 28 | let value = MyStruct { foo = 123 }; 29 | let my_schema = schema_for_value!(value); 30 | ``` 31 | 32 | 35 | -------------------------------------------------------------------------------- /schemars/tests/schema_name.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | use schemars::JsonSchema; 3 | use util::*; 4 | 5 | #[allow(dead_code)] 6 | #[derive(JsonSchema)] 7 | struct MyStruct { 8 | t: T, 9 | u: U, 10 | v: V, 11 | w: W, 12 | inner: MySimpleStruct, 13 | } 14 | 15 | #[allow(dead_code)] 16 | #[derive(JsonSchema)] 17 | struct MySimpleStruct { 18 | foo: i32, 19 | } 20 | 21 | #[test] 22 | fn default_name_multiple_type_params() -> TestResult { 23 | test_default_generated_schema::>>("schema-name-default") 24 | } 25 | 26 | #[allow(dead_code)] 27 | #[derive(JsonSchema)] 28 | #[serde(rename = "a-new-name-{W}-{T}-{T}")] 29 | #[schemars(rename_all = "camelCase")] 30 | struct MyRenamedStruct { 31 | t: T, 32 | u: U, 33 | v: V, 34 | w: W, 35 | inner: MySimpleRenamedStruct, 36 | } 37 | 38 | #[allow(dead_code)] 39 | #[derive(JsonSchema)] 40 | #[serde(rename = "this-attribute-is-ignored")] 41 | #[schemars(rename = "another-new-name")] 42 | struct MySimpleRenamedStruct { 43 | foo: i32, 44 | } 45 | 46 | #[test] 47 | fn overriden_with_rename_multiple_type_params() -> TestResult { 48 | test_default_generated_schema::>>( 49 | "schema-name-custom", 50 | ) 51 | } 52 | 53 | #[allow(dead_code)] 54 | #[derive(JsonSchema)] 55 | #[schemars(rename = "const-generics-{BAR}-")] 56 | struct ConstGenericStruct { 57 | foo: i32, 58 | } 59 | 60 | #[test] 61 | fn overriden_with_rename_const_generics() -> TestResult { 62 | test_default_generated_schema::>("schema-name-const-generics") 63 | } 64 | 65 | #[allow(dead_code)] 66 | #[derive(JsonSchema)] 67 | struct MixedGenericStruct { 68 | generic: T, 69 | foo: i32, 70 | } 71 | 72 | #[test] 73 | fn default_name_mixed_generics() -> TestResult { 74 | test_default_generated_schema::>, 42, 'z'>>( 75 | "schema-name-mixed-generics", 76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /schemars/tests/expected/range.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyStruct", 4 | "type": "object", 5 | "required": [ 6 | "bound", 7 | "inclusive", 8 | "range" 9 | ], 10 | "properties": { 11 | "range": { 12 | "$ref": "#/definitions/Range_of_uint" 13 | }, 14 | "inclusive": { 15 | "$ref": "#/definitions/Range_of_double" 16 | }, 17 | "bound": { 18 | "$ref": "#/definitions/Bound_of_String" 19 | } 20 | }, 21 | "definitions": { 22 | "Range_of_uint": { 23 | "type": "object", 24 | "required": [ 25 | "end", 26 | "start" 27 | ], 28 | "properties": { 29 | "start": { 30 | "type": "integer", 31 | "format": "uint", 32 | "minimum": 0.0 33 | }, 34 | "end": { 35 | "type": "integer", 36 | "format": "uint", 37 | "minimum": 0.0 38 | } 39 | } 40 | }, 41 | "Range_of_double": { 42 | "type": "object", 43 | "required": [ 44 | "end", 45 | "start" 46 | ], 47 | "properties": { 48 | "start": { 49 | "type": "number", 50 | "format": "double" 51 | }, 52 | "end": { 53 | "type": "number", 54 | "format": "double" 55 | } 56 | } 57 | }, 58 | "Bound_of_String": { 59 | "oneOf": [ 60 | { 61 | "type": "object", 62 | "required": [ 63 | "Included" 64 | ], 65 | "properties": { 66 | "Included": { 67 | "type": "string" 68 | } 69 | } 70 | }, 71 | { 72 | "type": "object", 73 | "required": [ 74 | "Excluded" 75 | ], 76 | "properties": { 77 | "Excluded": { 78 | "type": "string" 79 | } 80 | } 81 | }, 82 | { 83 | "type": "string", 84 | "const": "Unbounded" 85 | } 86 | ] 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /schemars/tests/expected/schema_with-enum-adjacent-tagged.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "Adjacent", 4 | "oneOf": [ 5 | { 6 | "type": "object", 7 | "required": [ 8 | "c", 9 | "t" 10 | ], 11 | "properties": { 12 | "c": { 13 | "type": "object", 14 | "required": [ 15 | "foo" 16 | ], 17 | "properties": { 18 | "foo": { 19 | "type": "boolean" 20 | } 21 | } 22 | }, 23 | "t": { 24 | "type": "string", 25 | "enum": [ 26 | "Struct" 27 | ] 28 | } 29 | } 30 | }, 31 | { 32 | "type": "object", 33 | "required": [ 34 | "c", 35 | "t" 36 | ], 37 | "properties": { 38 | "c": { 39 | "type": "boolean" 40 | }, 41 | "t": { 42 | "type": "string", 43 | "enum": [ 44 | "NewType" 45 | ] 46 | } 47 | } 48 | }, 49 | { 50 | "type": "object", 51 | "required": [ 52 | "c", 53 | "t" 54 | ], 55 | "properties": { 56 | "c": { 57 | "type": "array", 58 | "items": [ 59 | { 60 | "type": "boolean" 61 | }, 62 | { 63 | "type": "integer", 64 | "format": "int32" 65 | } 66 | ], 67 | "maxItems": 2, 68 | "minItems": 2 69 | }, 70 | "t": { 71 | "type": "string", 72 | "enum": [ 73 | "Tuple" 74 | ] 75 | } 76 | } 77 | }, 78 | { 79 | "type": "object", 80 | "required": [ 81 | "c", 82 | "t" 83 | ], 84 | "properties": { 85 | "c": { 86 | "type": "boolean" 87 | }, 88 | "t": { 89 | "type": "string", 90 | "enum": [ 91 | "Unit" 92 | ] 93 | } 94 | } 95 | } 96 | ] 97 | } -------------------------------------------------------------------------------- /docs/4-features.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Feature Flags 4 | nav_order: 5 5 | permalink: /features/ 6 | --- 7 | 8 | # Feature Flags and Optional Dependencies 9 | 10 | - `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro 11 | - `impl_json_schema` - implements `JsonSchema` for Schemars types themselves 12 | - `preserve_order` - keep the order of struct fields in `Schema` and `SchemaObject` 13 | - `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature) 14 | 15 | Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets): 16 | 17 | - `chrono` - [chrono](https://crates.io/crates/chrono) (^0.4) 18 | - `indexmap1` - [indexmap](https://crates.io/crates/indexmap) (^1.2) 19 | - `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0) 20 | - `either` - [either](https://crates.io/crates/either) (^1.3) 21 | - `uuid08` - [uuid](https://crates.io/crates/uuid) (^0.8) 22 | - `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0) 23 | - `smallvec` - [smallvec](https://crates.io/crates/smallvec) (^1.0) 24 | - `arrayvec05` - [arrayvec](https://crates.io/crates/arrayvec) (^0.5) 25 | - `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7) 26 | - `url` - [url](https://crates.io/crates/url) (^2.0) 27 | - `bytes` - [bytes](https://crates.io/crates/bytes) (^1.0) 28 | - `enumset` - [enumset](https://crates.io/crates/enumset) (^1.0) 29 | - `rust_decimal` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0) 30 | - `bigdecimal03` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.3) 31 | - `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4) 32 | - `smol_str` - [smol_str](https://crates.io/crates/smol_str) (^0.1.17) 33 | - `semver` - [semver](https://crates.io/crates/semver) (^1.0.9) 34 | 35 | For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so: 36 | 37 | ```toml 38 | [dependencies] 39 | schemars = { version = "0.8", features = ["chrono"] } 40 | ``` 41 | -------------------------------------------------------------------------------- /schemars_derive/src/regex_syntax.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::all)] 2 | // Copied from regex_syntax crate to avoid pulling in the whole crate just for a utility function 3 | // https://github.com/rust-lang/regex/blob/431c4e4867e1eb33eb39b23ed47c9934b2672f8f/regex-syntax/src/lib.rs 4 | // 5 | // Copyright (c) 2014 The Rust Project Developers 6 | // 7 | // Permission is hereby granted, free of charge, to any 8 | // person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the 10 | // Software without restriction, including without 11 | // limitation the rights to use, copy, modify, merge, 12 | // publish, distribute, sublicense, and/or sell copies of 13 | // the Software, and to permit persons to whom the Software 14 | // is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice 18 | // shall be included in all copies or substantial portions 19 | // of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 22 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 23 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 24 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 25 | // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 26 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 28 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | // DEALINGS IN THE SOFTWARE. 30 | 31 | pub fn escape(text: &str) -> String { 32 | let mut quoted = String::new(); 33 | escape_into(text, &mut quoted); 34 | quoted 35 | } 36 | 37 | fn escape_into(text: &str, buf: &mut String) { 38 | buf.reserve(text.len()); 39 | for c in text.chars() { 40 | if is_meta_character(c) { 41 | buf.push('\\'); 42 | } 43 | buf.push(c); 44 | } 45 | } 46 | 47 | fn is_meta_character(c: char) -> bool { 48 | match c { 49 | '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' 50 | | '#' | '&' | '-' | '~' => true, 51 | _ => false, 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /schemars/src/json_schema_impls/chrono.rs: -------------------------------------------------------------------------------- 1 | use crate::r#gen::SchemaGenerator; 2 | use crate::schema::*; 3 | use crate::JsonSchema; 4 | use chrono::prelude::*; 5 | use serde_json::json; 6 | use std::borrow::Cow; 7 | 8 | impl JsonSchema for Weekday { 9 | no_ref_schema!(); 10 | 11 | fn schema_name() -> String { 12 | "Weekday".to_owned() 13 | } 14 | 15 | fn schema_id() -> Cow<'static, str> { 16 | Cow::Borrowed("chrono::Weekday") 17 | } 18 | 19 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 20 | SchemaObject { 21 | instance_type: Some(InstanceType::String.into()), 22 | enum_values: Some(vec![ 23 | json!("Mon"), 24 | json!("Tue"), 25 | json!("Wed"), 26 | json!("Thu"), 27 | json!("Fri"), 28 | json!("Sat"), 29 | json!("Sun"), 30 | ]), 31 | ..Default::default() 32 | } 33 | .into() 34 | } 35 | } 36 | 37 | macro_rules! formatted_string_impl { 38 | ($ty:ident, $format:literal) => { 39 | formatted_string_impl!($ty, $format, JsonSchema for $ty); 40 | }; 41 | ($ty:ident, $format:literal, $($desc:tt)+) => { 42 | impl $($desc)+ { 43 | no_ref_schema!(); 44 | 45 | fn schema_name() -> String { 46 | stringify!($ty).to_owned() 47 | } 48 | 49 | fn schema_id() -> Cow<'static, str> { 50 | Cow::Borrowed(stringify!(chrono::$ty)) 51 | } 52 | 53 | fn json_schema(_: &mut SchemaGenerator) -> Schema { 54 | SchemaObject { 55 | instance_type: Some(InstanceType::String.into()), 56 | format: Some($format.to_owned()), 57 | ..Default::default() 58 | } 59 | .into() 60 | } 61 | } 62 | }; 63 | } 64 | 65 | formatted_string_impl!(NaiveDate, "date"); 66 | formatted_string_impl!(NaiveDateTime, "partial-date-time"); 67 | formatted_string_impl!(NaiveTime, "partial-date-time"); 68 | formatted_string_impl!(DateTime, "date-time", JsonSchema for DateTime); 69 | -------------------------------------------------------------------------------- /schemars_derive/src/metadata.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct SchemaMetadata<'a> { 5 | pub title: Option<&'a str>, 6 | pub description: Option<&'a str>, 7 | pub deprecated: bool, 8 | pub read_only: bool, 9 | pub write_only: bool, 10 | pub examples: &'a [syn::Path], 11 | pub default: Option, 12 | } 13 | 14 | impl<'a> SchemaMetadata<'a> { 15 | pub fn apply_to_schema(&self, schema_expr: &mut TokenStream) { 16 | if let Some(title) = &self.title { 17 | *schema_expr = quote! { 18 | schemars::_private::metadata::add_title(#schema_expr, #title) 19 | }; 20 | } 21 | if let Some(description) = &self.description { 22 | *schema_expr = quote! { 23 | schemars::_private::metadata::add_description(#schema_expr, #description) 24 | }; 25 | } 26 | 27 | if self.deprecated { 28 | *schema_expr = quote! { 29 | schemars::_private::metadata::add_deprecated(#schema_expr, true) 30 | }; 31 | } 32 | 33 | if self.read_only { 34 | *schema_expr = quote! { 35 | schemars::_private::metadata::add_read_only(#schema_expr, true) 36 | }; 37 | } 38 | if self.write_only { 39 | *schema_expr = quote! { 40 | schemars::_private::metadata::add_write_only(#schema_expr, true) 41 | }; 42 | } 43 | 44 | if !self.examples.is_empty() { 45 | let examples = self.examples.iter().map(|eg| { 46 | quote! { 47 | schemars::_serde_json::value::to_value(#eg()) 48 | } 49 | }); 50 | 51 | *schema_expr = quote! { 52 | schemars::_private::metadata::add_examples(#schema_expr, [#(#examples),*].into_iter().flatten()) 53 | }; 54 | } 55 | 56 | if let Some(default) = &self.default { 57 | *schema_expr = quote! { 58 | schemars::_private::metadata::add_default(#schema_expr, #default.and_then(|d| schemars::_schemars_maybe_to_value!(d))) 59 | }; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /schemars/examples/doc_comments.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "My Amazing Struct", 4 | "description": "This struct shows off generating a schema with\na custom title and description.", 5 | "type": "object", 6 | "required": [ 7 | "my_bool", 8 | "my_int" 9 | ], 10 | "properties": { 11 | "my_bool": { 12 | "description": "This bool has a description, but no title.", 13 | "type": "boolean" 14 | }, 15 | "my_int": { 16 | "title": "My Amazing Integer", 17 | "type": "integer", 18 | "format": "int32" 19 | }, 20 | "my_nullable_enum": { 21 | "title": "A Nullable Enum", 22 | "description": "This enum might be set, or it might not.", 23 | "anyOf": [ 24 | { 25 | "$ref": "#/definitions/MyEnum" 26 | }, 27 | { 28 | "type": "null" 29 | } 30 | ] 31 | } 32 | }, 33 | "definitions": { 34 | "MyEnum": { 35 | "title": "My Amazing Enum", 36 | "oneOf": [ 37 | { 38 | "description": "A wrapper around a `String`", 39 | "type": "object", 40 | "required": [ 41 | "StringNewType" 42 | ], 43 | "properties": { 44 | "StringNewType": { 45 | "type": "string" 46 | } 47 | }, 48 | "additionalProperties": false 49 | }, 50 | { 51 | "description": "A struct-like enum variant which contains\nsome floats", 52 | "type": "object", 53 | "required": [ 54 | "StructVariant" 55 | ], 56 | "properties": { 57 | "StructVariant": { 58 | "type": "object", 59 | "required": [ 60 | "floats" 61 | ], 62 | "properties": { 63 | "floats": { 64 | "description": "The floats themselves", 65 | "type": "array", 66 | "items": { 67 | "type": "number", 68 | "format": "float" 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | "additionalProperties": false 75 | } 76 | ] 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /docs/_includes/examples/doc_comments.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "My Amazing Struct", 4 | "description": "This struct shows off generating a schema with\na custom title and description.", 5 | "type": "object", 6 | "required": [ 7 | "my_bool", 8 | "my_int" 9 | ], 10 | "properties": { 11 | "my_bool": { 12 | "description": "This bool has a description, but no title.", 13 | "type": "boolean" 14 | }, 15 | "my_int": { 16 | "title": "My Amazing Integer", 17 | "type": "integer", 18 | "format": "int32" 19 | }, 20 | "my_nullable_enum": { 21 | "title": "A Nullable Enum", 22 | "description": "This enum might be set, or it might not.", 23 | "anyOf": [ 24 | { 25 | "$ref": "#/definitions/MyEnum" 26 | }, 27 | { 28 | "type": "null" 29 | } 30 | ] 31 | } 32 | }, 33 | "definitions": { 34 | "MyEnum": { 35 | "title": "My Amazing Enum", 36 | "oneOf": [ 37 | { 38 | "description": "A wrapper around a `String`", 39 | "type": "object", 40 | "required": [ 41 | "StringNewType" 42 | ], 43 | "properties": { 44 | "StringNewType": { 45 | "type": "string" 46 | } 47 | }, 48 | "additionalProperties": false 49 | }, 50 | { 51 | "description": "A struct-like enum variant which contains\nsome floats", 52 | "type": "object", 53 | "required": [ 54 | "StructVariant" 55 | ], 56 | "properties": { 57 | "StructVariant": { 58 | "type": "object", 59 | "required": [ 60 | "floats" 61 | ], 62 | "properties": { 63 | "floats": { 64 | "description": "The floats themselves", 65 | "type": "array", 66 | "items": { 67 | "type": "number", 68 | "format": "float" 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | "additionalProperties": false 75 | } 76 | ] 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /schemars/tests/ui/invalid_validation_attrs.stderr: -------------------------------------------------------------------------------- 1 | error: expected validate regex attribute to be a string: `regex = "..."` 2 | --> $DIR/invalid_validation_attrs.rs:4:39 3 | | 4 | 4 | pub struct Struct1(#[validate(regex = 0, foo, length(min = 1, equal = 2, bar))] String); 5 | | ^ 6 | 7 | error: unknown schemars attribute `foo` 8 | --> $DIR/invalid_validation_attrs.rs:7:42 9 | | 10 | 7 | pub struct Struct2(#[schemars(regex = 0, foo, length(min = 1, equal = 2, bar))] String); 11 | | ^^^ 12 | 13 | error: expected schemars regex attribute to be a string: `regex = "..."` 14 | --> $DIR/invalid_validation_attrs.rs:7:39 15 | | 16 | 7 | pub struct Struct2(#[schemars(regex = 0, foo, length(min = 1, equal = 2, bar))] String); 17 | | ^ 18 | 19 | error: schemars attribute cannot contain both `equal` and `min` 20 | --> $DIR/invalid_validation_attrs.rs:7:63 21 | | 22 | 7 | pub struct Struct2(#[schemars(regex = 0, foo, length(min = 1, equal = 2, bar))] String); 23 | | ^^^^^ 24 | 25 | error: unknown item in schemars length attribute 26 | --> $DIR/invalid_validation_attrs.rs:7:74 27 | | 28 | 7 | pub struct Struct2(#[schemars(regex = 0, foo, length(min = 1, equal = 2, bar))] String); 29 | | ^^^ 30 | 31 | error: schemars attribute cannot contain both `contains` and `regex` 32 | --> $DIR/invalid_validation_attrs.rs:26:9 33 | | 34 | 26 | contains = "bar", 35 | | ^^^^^^^^ 36 | 37 | error: duplicate schemars attribute `regex` 38 | --> $DIR/invalid_validation_attrs.rs:27:9 39 | | 40 | 27 | regex(path = "baz"), 41 | | ^^^^^ 42 | 43 | error: schemars attribute cannot contain both `phone` and `email` 44 | --> $DIR/invalid_validation_attrs.rs:29:9 45 | | 46 | 29 | email, 47 | | ^^^^^ 48 | 49 | error: schemars attribute cannot contain both `phone` and `url` 50 | --> $DIR/invalid_validation_attrs.rs:30:9 51 | | 52 | 30 | url 53 | | ^^^ 54 | 55 | error[E0425]: cannot find value `foo` in this scope 56 | --> $DIR/invalid_validation_attrs.rs:12:17 57 | | 58 | 12 | regex = "foo", 59 | | ^^^^^ not found in this scope 60 | --------------------------------------------------------------------------------