7 releases ()
1.0.0-alpha.2 | Jun 27, 2024 |
---|---|
0.8.21 | May 26, 2024 |
0.8.17 | Apr 29, 2024 |
0.8.16 | Jan 18, 2024 |
#145 in #json-schema
2,089 downloads per month
Used in apistos-schemars
86KB
2K
SLoC
Apistos Schemars
Generate JSON Schema documents from Rust code
⚠️ Warning
This is a fork of the official schemars repository which only exists until this PR is merged. It is published on crates.io with the name apistos-schemars and apistos-schemars_derive This fork is based on schemars master and rebased from time to time.
Basic Usage
If you don't really care about the specifics, the easiest way to generate a JSON schema for your types is to #[derive(JsonSchema)]
and use the schema_for!
macro. All fields of the type must also implement JsonSchema
- Schemars implements this for many standard library types.
extern crate apistos_schemars as schemars;
use schemars::{schema_for, JsonSchema};
#[derive(JsonSchema)]
pub struct MyStruct {
pub my_int: i32,
pub my_bool: bool,
pub my_nullable_enum: Option<MyEnum>,
}
#[derive(JsonSchema)]
pub enum MyEnum {
StringNewType(String),
StructVariant { floats: Vec<f32> },
}
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": {
"my_bool": {
"type": "boolean"
},
"my_int": {
"type": "integer",
"format": "int32"
},
"my_nullable_enum": {
"anyOf": [
{
"$ref": "#/$defs/MyEnum"
},
{
"type": "null"
}
]
}
},
"required": ["my_int", "my_bool"],
"$defs": {
"MyEnum": {
"oneOf": [
{
"type": "object",
"properties": {
"StringNewType": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["StringNewType"]
},
{
"type": "object",
"properties": {
"StructVariant": {
"type": "object",
"properties": {
"floats": {
"type": "array",
"items": {
"type": "number",
"format": "float"
}
}
},
"required": ["floats"]
}
},
"additionalProperties": false,
"required": ["StructVariant"]
}
]
}
}
}
Serde Compatibility
One of the main aims of this library is compatibility with Serde. Any generated schema should match how serde_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.
extern crate apistos_schemars as schemars;
use schemars::{schema_for, JsonSchema};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct MyStruct {
#[serde(rename = "myNumber")]
pub my_int: i32,
pub my_bool: bool,
#[serde(default)]
pub my_nullable_enum: Option<MyEnum>,
}
#[derive(Deserialize, Serialize, JsonSchema)]
#[serde(untagged)]
pub enum MyEnum {
StringNewType(String),
StructVariant { floats: Vec<f32> },
}
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": {
"myBool": {
"type": "boolean"
},
"myNullableEnum": {
"anyOf": [
{
"$ref": "#/$defs/MyEnum"
},
{
"type": "null"
}
],
"default": null
},
"myNumber": {
"type": "integer",
"format": "int32"
}
},
"additionalProperties": false,
"required": ["myNumber", "myBool"],
"$defs": {
"MyEnum": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"floats": {
"type": "array",
"items": {
"type": "number",
"format": "float"
}
}
},
"required": ["floats"]
}
]
}
}
}
#[serde(...)]
attributes can be overriden using #[schemars(...)]
attributes, which behave identically (e.g. #[schemars(rename_all = "camelCase")]
). You may find this useful if you want to change the generated schema without affecting Serde's behaviour, or if you're just not using Serde.
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. 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.
extern crate apistos_schemars as schemars;
use schemars::schema_for_value;
use serde::Serialize;
#[derive(Serialize)]
pub struct MyStruct {
pub my_int: i32,
pub my_bool: bool,
pub my_nullable_enum: Option<MyEnum>,
}
#[derive(Serialize)]
pub enum MyEnum {
StringNewType(String),
StructVariant { floats: Vec<f32> },
}
let schema = schema_for_value!(MyStruct {
my_int: 123,
my_bool: true,
my_nullable_enum: Some(MyEnum::StringNewType("foo".to_string()))
});
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
Click to see the output JSON schema...
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct",
"examples": [
{
"my_bool": true,
"my_int": 123,
"my_nullable_enum": {
"StringNewType": "foo"
}
}
],
"type": "object",
"properties": {
"my_bool": {
"type": "boolean"
},
"my_int": {
"type": "integer"
},
"my_nullable_enum": true
}
}
Feature Flags
derive
(enabled by default) - provides#[derive(JsonSchema)]
macropreserve_order
- keep the order of struct fields inSchema
propertiesraw_value
- implementsJsonSchema
forserde_json::value::RawValue
(enables the serde_jsonraw_value
feature)
Schemars can implement JsonSchema
on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets):
arrayvec07
- arrayvec (^0.7)bigdecimal04
- bigdecimal (^0.4)bytes1
- bytes (^1.0)chrono04
- chrono (^0.4)either1
- either (^1.3)enumset1
- enumset (^1.0)indexmap2
- indexmap (^2.0)ipnetwork
- ipnetwork (^0.20)rust_decimal1
- rust_decimal (^1.0)semver1
- semver (^1.0.9)smallvec1
- smallvec (^1.0)smol_str02
- smol_str (^0.2.1)url2
- url (^2.0)uuid1
- uuid (^1.0)
For example, to implement JsonSchema
on types from chrono
, enable it as a feature in the schemars
dependency in your Cargo.toml
like so:
[dependencies]
schemars = { version = "1.0.0-alpha.2", features = ["chrono04"] }
Dependencies
~0.4–0.8MB
~19K SLoC