diff --git a/docs/_includes/example.md b/docs/_includes/example.md index aca27b3..8868524 100644 --- a/docs/_includes/example.md +++ b/docs/_includes/example.md @@ -9,6 +9,6 @@ Click to see the output JSON schema... ```json -{% include {{ output }} %} +{% include {{ output }} -%} ``` diff --git a/docs/_includes/examples/custom_serialization.rs b/docs/_includes/examples/custom_serialization.rs new file mode 100644 index 0000000..2fc8fa9 --- /dev/null +++ b/docs/_includes/examples/custom_serialization.rs @@ -0,0 +1,48 @@ +use schemars::{schema_for, JsonSchema}; +use serde::{Deserialize, Serialize}; + +// `int_as_string` and `bool_as_string` use the schema for `String`. +#[derive(Default, Deserialize, Serialize, JsonSchema)] +pub struct MyStruct { + #[serde(default = "eight", with = "as_string")] + #[schemars(with = "String")] + pub int_as_string: i32, + #[serde(default = "eight")] + pub int_normal: i32, + #[serde(default, with = "as_string")] + #[schemars(with = "String")] + pub bool_as_string: bool, + #[serde(default)] + pub bool_normal: bool, +} + +fn eight() -> i32 { + 8 +} + +// This module serializes values as strings +mod as_string { + use serde::{de::Error, Deserialize, Deserializer, Serializer}; + + pub fn serialize(value: &T, serializer: S) -> Result + where + T: std::fmt::Display, + S: Serializer, + { + serializer.collect_str(value) + } + + pub fn deserialize<'de, T, D>(deserializer: D) -> Result + where + T: std::str::FromStr, + D: Deserializer<'de>, + { + let string = String::deserialize(deserializer)?; + string.parse().map_err(|_| D::Error::custom("Input was not valid")) + } +} + +fn main() { + let schema = schema_for!(MyStruct); + println!("{}", serde_json::to_string_pretty(&schema).unwrap()); +} diff --git a/docs/_includes/examples/custom_serialization.schema.json b/docs/_includes/examples/custom_serialization.schema.json new file mode 100644 index 0000000..017a143 --- /dev/null +++ b/docs/_includes/examples/custom_serialization.schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MyStruct", + "type": "object", + "properties": { + "bool_as_string": { + "default": "false", + "type": "string" + }, + "bool_normal": { + "default": false, + "type": "boolean" + }, + "int_as_string": { + "default": "8", + "type": "string" + }, + "int_normal": { + "default": 8, + "type": "integer", + "format": "int32" + } + } +} diff --git a/docs/_sass/overrides.scss b/docs/_sass/overrides.scss index 8ad4259..ed7fe1a 100644 --- a/docs/_sass/overrides.scss +++ b/docs/_sass/overrides.scss @@ -52,4 +52,8 @@ code { details summary { display: list-item; cursor: pointer; +} + +details { + margin-bottom: 0.8rem; } \ No newline at end of file diff --git a/docs/examples/6-doc_comments.md b/docs/examples/6-doc_comments.md index 113ef64..9a5cdf9 100644 --- a/docs/examples/6-doc_comments.md +++ b/docs/examples/6-doc_comments.md @@ -2,7 +2,7 @@ layout: default title: Doc Comments parent: Examples -nav_order: 5 +nav_order: 6 summary: Giving schemas a custom title and/or description using doc comments. --- diff --git a/docs/examples/7-custom_serialization.md b/docs/examples/7-custom_serialization.md new file mode 100644 index 0000000..7005262 --- /dev/null +++ b/docs/examples/7-custom_serialization.md @@ -0,0 +1,20 @@ +--- +layout: default +title: Custom Serialization +parent: Examples +nav_order: 7 +summary: >- + If a field has a #[serde(with = "path")] attribute where "path" is not a type that implements JsonSchema, + then in order to derive JsonSchema on the type, it must also have a #[schemars(with = "Type")] attribute, + where "Type" implements JsonSchema. +--- + +# Deriving JsonSchema with Fields Using Custom Serialization + +Serde allows you to change how a field is (de)serialized by setting a [`#[serde(with = "path")]`](https://serde.rs/field-attrs.html#with) attribute, where `$path::serialize` and `$path::deserialize` must be functions with the correct signature. Schemars supports the same attribute, but `path` must be a type implementing `JsonSchema`. + +In order to derive `JsonSchema` on a type which includes a `#[serde(with = "path")]` attribute where `path` is not a type implementing `JsonSchema`, you'll need to override it with a suitable `#[schemars(with = "Type")]` attribute. + +{% include example.md name="custom_serialization" %} + +Note that the `default` values in the schema are serialized as strings where appropriate. diff --git a/schemars/examples/custom_serialization.rs b/schemars/examples/custom_serialization.rs new file mode 100644 index 0000000..2fc8fa9 --- /dev/null +++ b/schemars/examples/custom_serialization.rs @@ -0,0 +1,48 @@ +use schemars::{schema_for, JsonSchema}; +use serde::{Deserialize, Serialize}; + +// `int_as_string` and `bool_as_string` use the schema for `String`. +#[derive(Default, Deserialize, Serialize, JsonSchema)] +pub struct MyStruct { + #[serde(default = "eight", with = "as_string")] + #[schemars(with = "String")] + pub int_as_string: i32, + #[serde(default = "eight")] + pub int_normal: i32, + #[serde(default, with = "as_string")] + #[schemars(with = "String")] + pub bool_as_string: bool, + #[serde(default)] + pub bool_normal: bool, +} + +fn eight() -> i32 { + 8 +} + +// This module serializes values as strings +mod as_string { + use serde::{de::Error, Deserialize, Deserializer, Serializer}; + + pub fn serialize(value: &T, serializer: S) -> Result + where + T: std::fmt::Display, + S: Serializer, + { + serializer.collect_str(value) + } + + pub fn deserialize<'de, T, D>(deserializer: D) -> Result + where + T: std::str::FromStr, + D: Deserializer<'de>, + { + let string = String::deserialize(deserializer)?; + string.parse().map_err(|_| D::Error::custom("Input was not valid")) + } +} + +fn main() { + let schema = schema_for!(MyStruct); + println!("{}", serde_json::to_string_pretty(&schema).unwrap()); +} diff --git a/schemars/examples/custom_serialization.schema.json b/schemars/examples/custom_serialization.schema.json new file mode 100644 index 0000000..017a143 --- /dev/null +++ b/schemars/examples/custom_serialization.schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MyStruct", + "type": "object", + "properties": { + "bool_as_string": { + "default": "false", + "type": "string" + }, + "bool_normal": { + "default": false, + "type": "boolean" + }, + "int_as_string": { + "default": "8", + "type": "string" + }, + "int_normal": { + "default": 8, + "type": "integer", + "format": "int32" + } + } +}