This page is for the current stable release of Schemars (v0.8.x).
To view this page for the v1 version of Schemars, which is still under development, click here.
Deriving JsonSchema with Fields Using Custom Serialization
Serde allows you to change how a field is (de)serialized by setting a #[serde(with = "path")]
attribute, where $path::serialize
and $path::deserialize
must be functions with the correct signature. Schemars supports the same attribute, but path
must be a type implementing JsonSchema
.
In order to derive JsonSchema
on a type which includes a #[serde(with = "path")]
attribute where path
is not a type implementing JsonSchema
, you'll need to override it with a suitable #[schemars(with = "Type")]
or #[schemars(schema_with = "path")]
attribute.
use schemars::{schema_for, JsonSchema, Schema, SchemaGenerator};
use serde::{Deserialize, Serialize};
// `int_as_string` and `bool_as_string` use the schema for `String`.
#[derive(Default, Deserialize, Serialize, JsonSchema)]
pub struct MyStruct {
#[serde(default = "eight", with = "as_string")]
#[schemars(with = "String")]
pub int_as_string: i32,
#[serde(default = "eight")]
pub int_normal: i32,
#[serde(default, with = "as_string")]
#[schemars(schema_with = "make_custom_schema")]
pub bool_as_string: bool,
#[serde(default)]
pub bool_normal: bool,
}
fn make_custom_schema(generator: &mut SchemaGenerator) -> Schema {
let mut schema = String::json_schema(generator);
schema
.ensure_object()
.insert("format".into(), "boolean".into());
schema
}
fn eight() -> i32 {
8
}
// This module serializes values as strings
mod as_string {
use serde::{de::Error, Deserialize, Deserializer, Serializer};
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: std::fmt::Display,
S: Serializer,
{
serializer.collect_str(value)
}
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: std::str::FromStr,
D: Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;
string
.parse()
.map_err(|_| D::Error::custom("Input was not valid"))
}
}
fn main() {
let schema = schema_for!(MyStruct);
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
}
Click to see the output JSON schema...
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "MyStruct",
"type": "object",
"properties": {
"bool_as_string": {
"type": "string",
"format": "boolean",
"default": "false"
},
"bool_normal": {
"type": "boolean",
"default": false
},
"int_as_string": {
"type": "string",
"default": "8"
},
"int_normal": {
"type": "integer",
"format": "int32",
"default": 8
}
}
}
Note that the default
values in the schema are serialized as strings where appropriate.