diff --git a/docs/3-generating.md b/docs/3-generating.md index 64901697..623d0ccd 100644 --- a/docs/3-generating.md +++ b/docs/3-generating.md @@ -28,15 +28,14 @@ let my_schema = generator.into_root_schema_for::(); See the API documentation for more info on how to use those types for custom schema generation. +### Serialize vs. Deserialize contract + +Of particular note is the `contract` setting, which controls whether the generated schemas should describe how types are serialized or how they're *de*serialized. By default, this is set to `Deserialize`. If you instead want your schema to describe the serialization behaviour, modify the `contract` field of `SchemaSettings` or use the `for_serialize()` helper method: + +{% include example.md name="serialize_contract" %} + ## Schema from Example Value If you want a schema for a type that can't/doesn't implement `JsonSchema`, but does implement `serde::Serialize`, then you can generate a JSON schema from a value of that type using the [`schema_for_value!` macro](https://docs.rs/schemars/1.0.0--latest/schemars/macro.schema_for_value.html). However, this schema will generally be less precise than if the type implemented `JsonSchema` - particularly when it involves enums, since schemars will not make any assumptions about the structure of an enum based on a single variant. -```rust -let value = MyStruct { foo = 123 }; -let my_schema = schema_for_value!(value); -``` - - +{% include example.md name="from_value" %} diff --git a/docs/_includes/examples/serialize_contract.rs b/docs/_includes/examples/serialize_contract.rs new file mode 100644 index 00000000..3f8a9ea8 --- /dev/null +++ b/docs/_includes/examples/serialize_contract.rs @@ -0,0 +1,29 @@ +use schemars::{generate::SchemaSettings, JsonSchema}; +use serde::{Deserialize, Serialize}; + +#[derive(JsonSchema, Deserialize, Serialize)] +// The schema effectively ignores this `rename_all`, since it doesn't apply to serialization +#[serde(rename_all(deserialize = "PascalCase"))] +pub struct MyStruct { + pub my_int: i32, + #[serde(skip_deserializing)] + pub my_read_only_bool: bool, + // This property is excluded from the schema + #[serde(skip_serializing)] + pub my_write_only_bool: bool, + // This property is excluded from the "required" properties of the schema, because it may be + // be skipped during serialization + #[serde(skip_serializing_if = "str::is_empty")] + pub maybe_string: String, + pub definitely_string: String, +} + +fn main() { + // By default, generated schemas describe how types are deserialized. + // So we modify the settings here to instead generate schemas describing how it's serialized: + let settings = SchemaSettings::default().for_serialize(); + + let generator = settings.into_generator(); + let schema = generator.into_root_schema_for::(); + println!("{}", serde_json::to_string_pretty(&schema).unwrap()); +} diff --git a/docs/_includes/examples/serialize_contract.schema.json b/docs/_includes/examples/serialize_contract.schema.json new file mode 100644 index 00000000..f5e78f63 --- /dev/null +++ b/docs/_includes/examples/serialize_contract.schema.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "definitely_string": { + "type": "string" + }, + "maybe_string": { + "type": "string" + }, + "my_int": { + "type": "integer", + "format": "int32" + }, + "my_read_only_bool": { + "type": "boolean", + "default": false, + "readOnly": true + } + }, + "required": [ + "my_int", + "my_read_only_bool", + "definitely_string" + ] +} diff --git a/schemars/examples/serialize_contract.rs b/schemars/examples/serialize_contract.rs new file mode 100644 index 00000000..3f8a9ea8 --- /dev/null +++ b/schemars/examples/serialize_contract.rs @@ -0,0 +1,29 @@ +use schemars::{generate::SchemaSettings, JsonSchema}; +use serde::{Deserialize, Serialize}; + +#[derive(JsonSchema, Deserialize, Serialize)] +// The schema effectively ignores this `rename_all`, since it doesn't apply to serialization +#[serde(rename_all(deserialize = "PascalCase"))] +pub struct MyStruct { + pub my_int: i32, + #[serde(skip_deserializing)] + pub my_read_only_bool: bool, + // This property is excluded from the schema + #[serde(skip_serializing)] + pub my_write_only_bool: bool, + // This property is excluded from the "required" properties of the schema, because it may be + // be skipped during serialization + #[serde(skip_serializing_if = "str::is_empty")] + pub maybe_string: String, + pub definitely_string: String, +} + +fn main() { + // By default, generated schemas describe how types are deserialized. + // So we modify the settings here to instead generate schemas describing how it's serialized: + let settings = SchemaSettings::default().for_serialize(); + + let generator = settings.into_generator(); + let schema = generator.into_root_schema_for::(); + println!("{}", serde_json::to_string_pretty(&schema).unwrap()); +} diff --git a/schemars/examples/serialize_contract.schema.json b/schemars/examples/serialize_contract.schema.json new file mode 100644 index 00000000..f5e78f63 --- /dev/null +++ b/schemars/examples/serialize_contract.schema.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "definitely_string": { + "type": "string" + }, + "maybe_string": { + "type": "string" + }, + "my_int": { + "type": "integer", + "format": "int32" + }, + "my_read_only_bool": { + "type": "boolean", + "default": false, + "readOnly": true + } + }, + "required": [ + "my_int", + "my_read_only_bool", + "definitely_string" + ] +}