schemars/lib.rs
1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4/// The map type used by schemars types.
5///
6/// Currently a `BTreeMap` or `IndexMap` can be used, but this may change to a different implementation
7/// with a similar interface in a future version of schemars.
8/// The `IndexMap` will be used when the `preserve_order` feature flag is set.
9#[cfg(not(feature = "preserve_order"))]
10pub type Map<K, V> = std::collections::BTreeMap<K, V>;
11#[cfg(feature = "preserve_order")]
12pub type Map<K, V> = indexmap::IndexMap<K, V>;
13/// The set type used by schemars types.
14///
15/// Currently a `BTreeSet`, but this may change to a different implementation
16/// with a similar interface in a future version of schemars.
17pub type Set<T> = std::collections::BTreeSet<T>;
18
19/// A view into a single entry in a map, which may either be vacant or occupied.
20//
21/// This is constructed from the `entry` method on `BTreeMap` or `IndexMap`,
22/// depending on whether the `preserve_order` feature flag is set.
23#[cfg(not(feature = "preserve_order"))]
24pub type MapEntry<'a, K, V> = std::collections::btree_map::Entry<'a, K, V>;
25#[cfg(feature = "preserve_order")]
26pub type MapEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>;
27
28mod flatten;
29mod json_schema_impls;
30mod ser;
31#[macro_use]
32mod macros;
33
34/// This module is only public for use by `schemars_derive`. It should not need to be used by code
35/// outside of `schemars`, and should not be considered part of the public API.
36#[doc(hidden)]
37pub mod _private;
38pub mod gen;
39pub mod schema;
40pub mod visit;
41
42#[cfg(feature = "schemars_derive")]
43extern crate schemars_derive;
44use std::borrow::Cow;
45
46#[cfg(feature = "schemars_derive")]
47pub use schemars_derive::*;
48
49// Export serde_json so schemars_derive can use it
50#[doc(hidden)]
51pub use serde_json as _serde_json;
52
53use schema::Schema;
54
55/// A type which can be described as a JSON Schema document.
56///
57/// This is implemented for many Rust primitive and standard library types.
58///
59/// This can also be automatically derived on most custom types with `#[derive(JsonSchema)]`.
60///
61/// # Examples
62/// Deriving an implementation:
63/// ```
64/// use schemars::{schema_for, JsonSchema};
65///
66/// #[derive(JsonSchema)]
67/// struct MyStruct {
68/// foo: i32,
69/// }
70///
71/// let my_schema = schema_for!(MyStruct);
72/// ```
73///
74/// When manually implementing `JsonSchema`, as well as determining an appropriate schema,
75/// you will need to determine an appropriate name and ID for the type.
76/// For non-generic types, the type name/path are suitable for this:
77/// ```
78/// use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
79/// use std::borrow::Cow;
80///
81/// struct NonGenericType;
82///
83/// impl JsonSchema for NonGenericType {
84/// fn schema_name() -> String {
85/// // Exclude the module path to make the name in generated schemas clearer.
86/// "NonGenericType".to_owned()
87/// }
88///
89/// fn schema_id() -> Cow<'static, str> {
90/// // Include the module, in case a type with the same name is in another module/crate
91/// Cow::Borrowed(concat!(module_path!(), "::NonGenericType"))
92/// }
93///
94/// fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
95/// todo!()
96/// }
97/// }
98///
99/// assert_eq!(NonGenericType::schema_id(), <&mut NonGenericType>::schema_id());
100/// ```
101///
102/// But generic type parameters which may affect the generated schema should typically be included in the name/ID:
103/// ```
104/// use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
105/// use std::{borrow::Cow, marker::PhantomData};
106///
107/// struct GenericType<T>(PhantomData<T>);
108///
109/// impl<T: JsonSchema> JsonSchema for GenericType<T> {
110/// fn schema_name() -> String {
111/// format!("GenericType_{}", T::schema_name())
112/// }
113///
114/// fn schema_id() -> Cow<'static, str> {
115/// Cow::Owned(format!(
116/// "{}::GenericType<{}>",
117/// module_path!(),
118/// T::schema_id()
119/// ))
120/// }
121///
122/// fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
123/// todo!()
124/// }
125/// }
126///
127/// assert_eq!(<GenericType<i32>>::schema_id(), <&mut GenericType<&i32>>::schema_id());
128/// ```
129///
130
131pub trait JsonSchema {
132 /// Whether JSON Schemas generated for this type should be re-used where possible using the `$ref` keyword.
133 ///
134 /// For trivial types (such as primitives), this should return `false`. For more complex types, it should return `true`.
135 /// For recursive types, this **must** return `true` to prevent infinite cycles when generating schemas.
136 ///
137 /// By default, this returns `true`.
138 fn is_referenceable() -> bool {
139 true
140 }
141
142 /// The name of the generated JSON Schema.
143 ///
144 /// This is used as the title for root schemas, and the key within the root's `definitions` property for subschemas.
145 fn schema_name() -> String;
146
147 /// Returns a string that uniquely identifies the schema produced by this type.
148 ///
149 /// This does not have to be a human-readable string, and the value will not itself be included in generated schemas.
150 /// If two types produce different schemas, then they **must** have different `schema_id()`s,
151 /// but two types that produce identical schemas should *ideally* have the same `schema_id()`.
152 ///
153 /// The default implementation returns the same value as `schema_name()`.
154 fn schema_id() -> Cow<'static, str> {
155 Cow::Owned(Self::schema_name())
156 }
157
158 /// Generates a JSON Schema for this type.
159 ///
160 /// If the returned schema depends on any [referenceable](JsonSchema::is_referenceable) schemas, then this method will
161 /// add them to the [`SchemaGenerator`](gen::SchemaGenerator)'s schema definitions.
162 ///
163 /// This should not return a `$ref` schema.
164 fn json_schema(gen: &mut gen::SchemaGenerator) -> Schema;
165
166 // TODO document and bring into public API?
167 #[doc(hidden)]
168 fn _schemars_private_non_optional_json_schema(gen: &mut gen::SchemaGenerator) -> Schema {
169 Self::json_schema(gen)
170 }
171
172 // TODO document and bring into public API?
173 #[doc(hidden)]
174 fn _schemars_private_is_option() -> bool {
175 false
176 }
177}
178
179#[cfg(test)]
180pub mod tests {
181 use super::*;
182
183 pub fn schema_object_for<T: JsonSchema>() -> schema::SchemaObject {
184 schema_object(schema_for::<T>())
185 }
186
187 pub fn schema_for<T: JsonSchema>() -> schema::Schema {
188 let mut gen = gen::SchemaGenerator::default();
189 T::json_schema(&mut gen)
190 }
191
192 pub fn schema_object(schema: schema::Schema) -> schema::SchemaObject {
193 match schema {
194 schema::Schema::Object(o) => o,
195 s => panic!("Schema was not an object: {:?}", s),
196 }
197 }
198}