diff --git a/docs/1-deriving.md b/docs/1-deriving.md index 6e37fc8..2c844ee 100644 --- a/docs/1-deriving.md +++ b/docs/1-deriving.md @@ -1,5 +1,4 @@ --- -layout: default title: Deriving JsonSchema nav_order: 2 has_children: true @@ -12,6 +11,7 @@ permalink: /deriving/ The most important trait in Schemars is `JsonSchema`, and the most important function of that trait is `json_schema(...)` which returns a JSON schema describing the type. Implementing this manually on many types would be slow and error-prone, so Schemars includes a derive macro which can implement that trait for you. Any derived implementation of `JsonSchema` should create a schema that describes the JSON representation of the type if it were to be serialized by serde_json. Usually, all you need to do to use it is to add a `#[derive(JsonSchema)]` attribute to your type: + ```rust use schemars::{JsonSchema, schema_for}; @@ -28,7 +28,8 @@ fn main() { println!("{}", serialized); } ``` - diff --git a/docs/_v0/1.1-attributes.md b/docs/_v0/1.1-attributes.md new file mode 100644 index 0000000..b668d7f --- /dev/null +++ b/docs/_v0/1.1-attributes.md @@ -0,0 +1,323 @@ +--- +title: Attributes +parent: Deriving JsonSchema +nav_order: 1 +permalink: /v0/deriving/attributes/ +--- + + + +# Attributes + +You can add attributes to your types to customize Schemars's derived `JsonSchema` implementation. + +[Serde](https://serde.rs/) allows setting `#[serde(...)]` attributes which change how types are serialized, and Schemars will generally respect these attributes to ensure that generated schemas will match how the type is serialized by serde_json. `#[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. + +[Validator](https://github.com/Keats/validator) allows setting `#[validate(...)]` attributes to restrict valid values of particular fields, many of which will be used by Schemars to generate more accurate schemas. These can also be overridden by `#[schemars(...)]` attributes. + +
+ +TABLE OF CONTENTS + + +1. [Supported Serde Attributes](#supported-serde-attributes) + - [`rename`](#rename) + - [`rename_all`](#rename_all) + - [`tag` / `content` / `untagged`](#tag) + - [`default`](#default) + - [`skip`](#skip) + - [`skip_serializing`](#skip_serializing) + - [`skip_deserializing`](#skip_deserializing) + - [`flatten`](#flatten) + - [`with`](#with) + - [`bound`](#bound) +1. [Supported Validator Attributes](#supported-validator-attributes) + - [`email` / `phone` / `url`](#email-phone-url) + - [`length`](#length) + - [`range`](#range) + - [`regex`](#regex) + - [`contains`](#contains) + - [`required` / `required_nested`](#required) +1. [Other Attributes](#other-attributes) + - [`schema_with`](#schema_with) + - [`title` / `description`](#title-description) + - [`example`](#example) + - [`deprecated`](#deprecated) + - [`crate`](#crate) + - [Doc Comments (`doc`)](#doc) + +
+ +## Supported Serde Attributes + +
+ +

+ +`#[serde(rename = "name")]` / `#[schemars(rename = "name")]` + +

+ +Set on a struct, enum, field or variant to use the given name in the generated schema instead of the Rust name. When used on a struct or enum, the given name will be used as the title for root schemas, and the key within the root's `definitions` property for subschemas. + +If set on a struct or enum with generic type parameters, then the given name may contain them enclosed in curly braces (e.g. `{T}`) and they will be replaced with the concrete type names when the schema is generated. + +Serde docs: [container](https://serde.rs/container-attrs.html#rename) / [variant](https://serde.rs/variant-attrs.html#rename) / [field](https://serde.rs/field-attrs.html#rename) + +

+ +`#[serde(rename_all = "...")]` / `#[schemars(rename_all = "...")]` + +

+ +Set on a struct, enum or variant to rename all fields according to the given case convention (see the Serde docs for details). + +Serde docs: [container](https://serde.rs/container-attrs.html#rename_all) / [variant](https://serde.rs/variant-attrs.html#rename_all) + +

+ +`#[serde(tag = "type")]` / `#[schemars(tag = "type")]`
+`#[serde(tag = "t", content = "c")]` / `#[schemars(tag = "t", content = "c")]`
+`#[serde(untagged)]` / `#[schemars(untagged)]` + +

+ +Set on an enum to generate the schema for the [internally tagged](https://serde.rs/enum-representations.html#internally-tagged), [adjacently tagged](https://serde.rs/enum-representations.html#adjacently-tagged), or [untagged](https://serde.rs/enum-representations.html#untagged) representation of this enum. + +Serde docs: [`tag`](https://serde.rs/container-attrs.html#tag) / [`tag`+`content`](https://serde.rs/container-attrs.html#tag--content) / [`untagged`](https://serde.rs/container-attrs.html#untagged) + +

+ +`#[serde(default)]` / `#[schemars(default)]` / `#[serde(default = "path")]` / `#[schemars(default = "path")]` + +

+ +Set on a struct or field to give fields a default value, which excludes them from the schema's `required` properties. The default will also be set on the field's schema's `default` property, unless it is skipped by a [`skip_serializing_if`](https://serde.rs/field-attrs.html#skip_serializing_if) attribute on the field. Any [`serialize_with`](https://serde.rs/field-attrs.html#serialize_with) or [`with`](https://serde.rs/field-attrs.html#with) attribute set on the field will be used to serialize the default value. + +Serde docs: [container](https://serde.rs/container-attrs.html#default) / [field](https://serde.rs/field-attrs.html#default) + +

+ +`#[serde(skip)]` / `#[schemars(skip)]` + +

+ +Set on a variant or field to prevent it from appearing in any generated schema. + +Serde docs: [variant](https://serde.rs/variant-attrs.html#skip) / [field](https://serde.rs/field-attrs.html#skip) + +

+ +`#[serde(skip_serializing)]` / `#[schemars(skip_serializing)]` + +

+ +Set on a field of a (non-tuple) struct to set the `writeOnly` property on that field's schema. Serde also allows this attribute on variants or tuple struct fields, but this will have no effect on generated schemas. + +Serde docs: [field](https://serde.rs/field-attrs.html#skip_deserializing) + +

+ +`#[serde(skip_deserializing)]` / `#[schemars(skip_deserializing)]` + +

+ +Set on a variant or field. When set on a field of a (non-tuple) struct, that field's schema will have the `readOnly` property set. When set on a variant or tuple struct field Schemars will treat this the same as a [`skip`](#skip) attribute. + +Serde docs: [variant](https://serde.rs/variant-attrs.html#skip_deserializing) / [field](https://serde.rs/field-attrs.html#skip_deserializing) + +

+ +`#[serde(flatten)]` / `#[schemars(flatten)]` + +

+ +Set on a field to include that field's contents as though they belonged to the field's container. + +Serde docs: [field](https://serde.rs/field-attrs.html#flatten) + +

+ +`#[serde(with = "Type")]` / `#[schemars(with = "Type")]` + +

+ +Set on a variant or field to generate its schema as the given type instead of its actual type. Serde allows the `with` attribute to refer to any module path, but Schemars requires this to be an actual type which implements `JsonSchema`. + +If the given type has any required generic type parameters, then they must all be explicitly specified in this attribute. Serde frequently allows you to omit them as it can make use of type inference, but unfortunately this is not possible with Schemars. For example, `with = "Vec::"` will work, but `with = "Vec"` and `with = "Vec::<_>"` will not. + +Serde docs: [variant](https://serde.rs/variant-attrs.html#with) / [field](https://serde.rs/field-attrs.html#with) + +

+ +`#[serde(deny_unknown_fields)]` / `#[schemars(deny_unknown_fields)]` + +

+ +Setting this on a container will set the `additionalProperties` keyword on generated schemas to `false` to show that any extra properties are explicitly disallowed. + +Serde docs: [container](https://serde.rs/container-attrs.html#deny_unknown_fields) + +

+ +`#[serde(transparent)]` / `#[schemars(transparent)]` + +

+ +Set on a newtype struct or a braced struct with one field to make the struct's generated schema exactly the same as that of the single field's. + +Serde docs: [container](https://serde.rs/container-attrs.html#transparent) + +

+ +`#[schemars(bound = "...")]` + +

+ +Where-clause for the JsonSchema impl. This replaces any trait bounds inferred by schemars. Schemars does **not** use trait bounds from `#[serde(bound)]` attributes. + +Serde docs: [container](https://serde.rs/container-attrs.html#bound) + +
+ +## Supported Validator Attributes + +
+ +

+ +`#[validate(email)]` / `#[schemars(email)]`
+`#[validate(phone)]` / `#[schemars(phone)]`
+`#[validate(url)]` / `#[schemars(url)]` + +

+ +Sets the schema's `format` to `email`/`phone`/`uri`, as appropriate. Only one of these attributes may be present on a single field. + +Validator docs: [email](https://github.com/Keats/validator#email) / [phone](https://github.com/Keats/validator#phone) / [url](https://github.com/Keats/validator#url) + +

+ +`#[validate(length(min = 1, max = 10))]` / `#[schemars(length(min = 1, max = 10))]`
+`#[validate(length(equal = 10))]` / `#[schemars(length(equal = 10))]` + +

+ +Sets the `minLength`/`maxLength` properties for string schemas, or the `minItems`/`maxItems` properties for array schemas. + +Validator docs: [length](https://github.com/Keats/validator#length) + +

+ +`#[validate(range(min = 1, max = 10))]` / `#[schemars(range(min = 1, max = 10))]` + +

+ +Sets the `minimum`/`maximum` properties for number schemas. + +Validator docs: [range](https://github.com/Keats/validator#range) + +

+ +`#[validate(regex = "path::to::regex")]` / `#[schemars(regex = "path::to::regex")]`
+`#[schemars(regex(pattern = r"^\d+$"))]` + +

+ +Sets the `pattern` property for string schemas. The `path::to::regex` will typically refer to a [`Regex`](https://docs.rs/regex/*/regex/struct.Regex.html) instance, but Schemars allows it to be any value with a `to_string()` method. + +Providing an inline regex pattern using `regex(pattern = ...)` is a Schemars extension, and not currently supported by the Validator crate. When using this form, you may want to use a `r"raw string literal"` so that `\\` characters in the regex pattern are not interpreted as escape sequences in the string. + +Validator docs: [regex](https://github.com/Keats/validator#regex) + +

+ +`#[validate(contains = "string")]` / `#[schemars(contains = "string")]` + +

+ +For string schemas, sets the `pattern` property to the given value, with any regex special characters escaped. For object schemas (e.g. when the attribute is set on a HashMap field), includes the value in the `required` property, indicating that the map must contain it as a key. + +Validator docs: [contains](https://github.com/Keats/validator#contains) + +

+ +`#[validate(required)]` / `#[schemars(required)]`
+`#[validate(required_nested)]` + +

+ +When set on an `Option` field, this will create a schemas as though the field were a `T`. + +Validator docs: [required](https://github.com/Keats/validator#required) / [required_nested](https://github.com/Keats/validator#required_nested) + +
+ +## Other Attributes + +

+ +`#[schemars(schema_with = "some::function")]` + +

+ +Set on a variant or field to generate this field's schema using the given function. This function must be callable as `fn(&mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema`. + +

+ +`#[schemars(title = "Some title", description = "Some description")]` + +

+ +Set on a container, variant or field to set the generated schema's `title` and/or `description`. If present, these will be used instead of values from any [`doc` comments/attributes](#doc). + +

+ +`#[schemars(example = "some::function")]` + +

+ +Set on a container, variant or field to include the result of the given function in the generated schema's `examples`. The function should take no parameters and can return any type that implements serde's `Serialize` trait - it does not need to return the same type as the attached struct/field. This attribute can be repeated to specify multiple examples. + +

+ +`#[deprecated]` + +

+ +Set the Rust built-in [`deprecated`](https://doc.rust-lang.org/edition-guide/rust-2018/the-compiler/an-attribute-for-deprecation.html) attribute on a struct, enum, field or variant to set the generated schema's `deprecated` keyword to `true`. + +

+ +`#[schemars(crate = "other_crate::schemars")]` + +

+ +Set the path to the schemars crate instance the generated code should depend on. This is mostly useful for other crates that depend on schemars in their macros. + +

+ +`#[schemars(inner(...))]` + +

+ +Sets properties specified by [validator attributes](#supported-validator-attributes) on items of an array schema. For example: + +```rs +struct Struct { + #[schemars(inner(url, regex(pattern = "^https://")))] + urls: Vec, +} +``` + +

+ +Doc Comments (`#[doc = "..."]`) + +

+ +If a struct, variant or field has any [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html#doc-comments) (or [`doc` attributes](https://doc.rust-lang.org/rustdoc/the-doc-attribute.html)), then these will be used as the generated schema's `description`. If the first line is an ATX-style markdown heading (i.e. it begins with a # character), then it will be used as the schema's `title`, and the remaining lines will be the `description`. diff --git a/docs/_v0/2-implementing.md b/docs/_v0/2-implementing.md new file mode 100644 index 0000000..32f4edd --- /dev/null +++ b/docs/_v0/2-implementing.md @@ -0,0 +1,78 @@ +--- +title: Implementing JsonSchema +nav_order: 3 +permalink: /v0/implementing/ +--- + +# Implementing JsonSchema + +[Deriving `JsonSchema`]({{ site.baseurl }}{% link 1-deriving.md %}) is usually the easiest way to enable JSON schema generation for your types. But if you need more customisation, you can also implement `JsonSchema` manually. This trait has two associated functions which must be implemented, and one which can optionally be implemented: + +## schema_name + +```rust +fn schema_name() -> String; +``` + +This function returns the human-readable friendly name of the type's schema, which frequently is just the name of the type itself. The schema name is used as the title for root schemas, and the key within the root's `definitions` property for subschemas. + +NB in a future version of schemars, it's likely that this function will be changed to return a `Cow<'static, str>`. + +## schema_id + +```rust +fn schema_id() -> Cow<'static, str>; +``` + +This function returns a unique identifier of the type's schema - if two types return the same `schema_id`, then Schemars will consider them identical types. Because of this, if a type takes any generic type parameters, then its ID should depend on the type arguments. For example, the implementation of this function for `Vec where T: JsonSchema` is: + +```rust +fn schema_id() -> Cow<'static, str> { + Cow::Owned( + format!("[{}]", T::schema_id())) +} +``` + +`&mut Vec<&T>`, `LinkedList`, `Mutex>>`, and similar collection types also use that implementation, since they produce identical JSON schemas so they can be considered the same type. + +For a type with no generic type arguments, a reasonable implementation of this function would be to return the type name including module path (in case there is a type with the same name in another module/crate), e.g.: + +```rust +impl JsonSchema for NonGenericType { + fn schema_name() -> String { + // Exclude the module path to make the name in generated schemas clearer. + "NonGenericType".to_owned() + } + + fn schema_id() -> Cow<'static, str> { + // Include the module, in case a type with the same name is in another module/crate + Cow::Borrowed(concat!(module_path!(), "::NonGenericType")) + } + + fn json_schema(_gen: &mut SchemaGenerator) -> Schema { + todo!() + } +} +``` + +## json_schema + +```rust +fn json_schema(gen: &mut gen::SchemaGenerator) -> Schema; +``` + +This function creates the JSON schema itself. The `gen` argument can be used to check the schema generation settings, or to get schemas for other types. If you do need schemas for other types, you should call the `gen.subschema_for::()` method instead of `::json_schema(gen)`, as `subschema_for` can add `T`'s schema to the root schema's `definitions` so that it does not need to be duplicated when used more than once. + +`json_schema` should not return a `$ref` schema. + +## is_referenceable (optional) + +```rust +fn is_referenceable() -> bool; +``` + +If this function returns `true`, then Schemars can re-use the generate schema where possible by adding it to the root schema's `definitions` and having other schemas reference it using the `$ref` keyword. This can greatly simplify schemas that include a particular type multiple times, especially if that type's schema is fairly complex. + +Generally, this should return `false` for types with simple schemas (such as primitives). For more complex types, it should return `true`. For recursive types, this **must** return `true` to prevent infinite cycles when generating schemas. + +The default implementation of this function returns `true` to reduce the chance of someone inadvertently causing infinite cycles with recursive types. diff --git a/docs/_v0/3-generating.md b/docs/_v0/3-generating.md new file mode 100644 index 0000000..ec56349 --- /dev/null +++ b/docs/_v0/3-generating.md @@ -0,0 +1,35 @@ +--- +title: Generating Schemas +nav_order: 4 +permalink: /v0/generating/ +--- + +# Generating Schemas + +The easiest way to generate a schema for a type that implements is to use the [`schema_for!` macro](https://docs.rs/schemars/latest/schemars/macro.schema_for.html), like so: + +```rust +let my_schema = schema_for!(MyStruct); +``` + +This will create a schema that conforms to [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. + +If you want more control over how the schema is generated, you can use the [`gen` module](https://docs.rs/schemars/latest/schemars/gen/). There are two main types in this module: + +- [`SchemaSettings`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaSettings.html), which defines what JSON Schema features should be used when generating schemas (for example, how `Option`s should be represented). +- [`SchemaGenerator`](https://docs.rs/schemars/latest/schemars/gen/struct.SchemaGenerator.html), which manages the generation of a schema document. + +See the API documentation for more info on how to use those types for custom schema generation. + +## 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/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); +``` + + diff --git a/docs/_v0/4-features.md b/docs/_v0/4-features.md new file mode 100644 index 0000000..4932fbe --- /dev/null +++ b/docs/_v0/4-features.md @@ -0,0 +1,39 @@ +--- +title: Feature Flags +nav_order: 5 +permalink: /v0/features/ +--- + +# Feature Flags and Optional Dependencies + +- `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro +- `impl_json_schema` - implements `JsonSchema` for Schemars types themselves +- `preserve_order` - keep the order of struct fields in `Schema` and `SchemaObject` +- `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature) + +Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets): + +- `chrono` - [chrono](https://crates.io/crates/chrono) (^0.4) +- `indexmap1` - [indexmap](https://crates.io/crates/indexmap) (^1.2) +- `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0) +- `either` - [either](https://crates.io/crates/either) (^1.3) +- `uuid08` - [uuid](https://crates.io/crates/uuid) (^0.8) +- `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0) +- `smallvec` - [smallvec](https://crates.io/crates/smallvec) (^1.0) +- `arrayvec05` - [arrayvec](https://crates.io/crates/arrayvec) (^0.5) +- `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7) +- `url` - [url](https://crates.io/crates/url) (^2.0) +- `bytes` - [bytes](https://crates.io/crates/bytes) (^1.0) +- `enumset` - [enumset](https://crates.io/crates/enumset) (^1.0) +- `rust_decimal` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0) +- `bigdecimal03` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.3) +- `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4) +- `smol_str` - [smol_str](https://crates.io/crates/smol_str) (^0.1.17) +- `semver` - [semver](https://crates.io/crates/semver) (^1.0.9) + +For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so: + +```toml +[dependencies] +schemars = { version = "0.8", features = ["chrono"] } +``` diff --git a/docs/_v0/5-examples.md b/docs/_v0/5-examples.md new file mode 100644 index 0000000..0df7e3d --- /dev/null +++ b/docs/_v0/5-examples.md @@ -0,0 +1,8 @@ +--- +title: Examples +nav_order: 6 +has_children: true +permalink: /v0/examples/ +--- + +# Examples diff --git a/docs/_v0/examples/1-derive_jsonschema.md b/docs/_v0/examples/1-derive_jsonschema.md new file mode 100644 index 0000000..590b799 --- /dev/null +++ b/docs/_v0/examples/1-derive_jsonschema.md @@ -0,0 +1,12 @@ +--- +title: Deriving JsonSchema +parent: Examples +nav_order: 1 +summary: Deriving JsonSchema on a struct and enum. +--- + +# Deriving JsonSchema + +This is the simplest usage of Schemars. Both types are made to derive `JsonSchema`, and the `schema_for!` macro is used to generate the schema itself. + +{% include example_v0.md name="main" %} diff --git a/docs/_v0/examples/2-serde_attrs.md b/docs/_v0/examples/2-serde_attrs.md new file mode 100644 index 0000000..b665319 --- /dev/null +++ b/docs/_v0/examples/2-serde_attrs.md @@ -0,0 +1,14 @@ +--- +title: Using Serde Attributes +parent: Examples +nav_order: 2 +summary: "Deriving JsonSchema on types that use #[serde] attributes to customise serialization behaviour." +--- + +# Using Serde Attributes + +One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/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. + +The list of supported `#[serde]` attributes are [documented here]({{ site.baseurl }}{% link 1.1-attributes.md %}#supported-serde-attributes). + +{% include example_v0.md name="serde_attrs" %} diff --git a/docs/_v0/examples/3-schemars_attrs.md b/docs/_v0/examples/3-schemars_attrs.md new file mode 100644 index 0000000..2a5de96 --- /dev/null +++ b/docs/_v0/examples/3-schemars_attrs.md @@ -0,0 +1,12 @@ +--- +title: Using Schemars Attributes +parent: Examples +nav_order: 3 +summary: "Deriving JsonSchema on types that use #[schemars] attributes to customise serialization behaviour." +--- + +# Using Serde Attributes + +`#[serde(...)]` attributes can be overriden (or replaced) with `#[schemars(...)]` attributes, which behave identically. 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. + +{% include example_v0.md name="schemars_attrs" %} diff --git a/docs/_v0/examples/4-custom_settings.md b/docs/_v0/examples/4-custom_settings.md new file mode 100644 index 0000000..e439f50 --- /dev/null +++ b/docs/_v0/examples/4-custom_settings.md @@ -0,0 +1,12 @@ +--- +title: Custom Schema Settings +parent: Examples +nav_order: 4 +summary: Generating a schema using custom settings which changes how Option is handled. +--- + +# Custom Schema Settings + +The `gen` module allows you to customise how schemas are generated. For example, the default behaviour for `Option` is to include `null` in the schema's `type`s, but we can instead add a `nullable` property to its schema: + +{% include example_v0.md name="custom_settings" %} diff --git a/docs/_v0/examples/5-remote_derive.md b/docs/_v0/examples/5-remote_derive.md new file mode 100644 index 0000000..ee0adb6 --- /dev/null +++ b/docs/_v0/examples/5-remote_derive.md @@ -0,0 +1,16 @@ +--- +title: Derive for Remote Crate +parent: Examples +nav_order: 5 +summary: Deriving JsonSchema implementations for a type in somebody else's crate. +--- + +# Deriving JsonSchema for a Type in a Different Crate + +Rust's [orphan rule](https://doc.rust-lang.org/book/traits.html#rules-for-implementing-traits) requires that either the trait or the type for which you are implementing the trait must be defined in the same crate as the impl, so it is not possible to implement `JsonSchema` for a type in a different crate directly. + +To work around this, Schemars provides a way of deriving `JsonSchema` implementations for types in other people's crates. The only catch is that you have to provide a definition of the type for Schemars's derive to process. + +This is the same way that Serde allows remote deriving, which is why this page reads so similarly to [Serde's documentation](https://serde.rs/remote-derive.html)! + +{% include example_v0.md name="remote_derive" %} diff --git a/docs/_v0/examples/6-doc_comments.md b/docs/_v0/examples/6-doc_comments.md new file mode 100644 index 0000000..24de317 --- /dev/null +++ b/docs/_v0/examples/6-doc_comments.md @@ -0,0 +1,12 @@ +--- +title: Doc Comments +parent: Examples +nav_order: 6 +summary: Giving schemas a custom title and/or description using doc comments. +--- + +# Setting a Custom Title and/or Description Using Doc Comments + +If a struct, variant or field has any [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html#doc-comments) (or [`doc` attributes](https://doc.rust-lang.org/rustdoc/the-doc-attribute.html)), then these will be used as the generated schema's `description`. If the first line is an ATX-style markdown heading (i.e. it begins with a # character), then it will be used as the schema's `title`, and the remaining lines will be the `description`. + +{% include example_v0.md name="doc_comments" %} diff --git a/docs/_v0/examples/7-custom_serialization.md b/docs/_v0/examples/7-custom_serialization.md new file mode 100644 index 0000000..499e670 --- /dev/null +++ b/docs/_v0/examples/7-custom_serialization.md @@ -0,0 +1,19 @@ +--- +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")]` or `#[schemars(schema_with = "path")]` attribute. + +{% include example_v0.md name="custom_serialization" %} + +Note that the `default` values in the schema are serialized as strings where appropriate. diff --git a/docs/_v0/examples/8-enum_repr.md b/docs/_v0/examples/8-enum_repr.md new file mode 100644 index 0000000..1cfcf81 --- /dev/null +++ b/docs/_v0/examples/8-enum_repr.md @@ -0,0 +1,13 @@ +--- +title: Serialize Enum as Number (serde_repr) +parent: Examples +nav_order: 8 +summary: >- + Generating a schema for with a C-like enum compatible with serde_repr. +--- + +# Serialize Enum as Number (serde_repr Compatibility) + +If you use the `#[repr(...)]` attribute on an enum to give it a C-like representation, then you may also want to use the [serde_repr](https://github.com/dtolnay/serde-repr) crate to serialize the enum values as numbers. In this case, you should use the corresponding `JsonSchema_repr` derive to ensure the schema for your type reflects how serde formats your type. + +{% include example_v0.md name="enum_repr" %} diff --git a/docs/_v0/examples/9-from_value.md b/docs/_v0/examples/9-from_value.md new file mode 100644 index 0000000..45198ff --- /dev/null +++ b/docs/_v0/examples/9-from_value.md @@ -0,0 +1,15 @@ +--- +title: Generate Schema from Example Value +parent: Examples +nav_order: 9 +summary: >- + Generating a schema for a serializable value. +--- + +# Generate Schema from Example Value + +If you want a schema for a type that can't/doesn't implement `JsonSchema`, but does implement [`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html), 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. + +{% include example_v0.md name="from_value" %} + +Note that the schema for the enum is not very useful in this case, since schemars doesn't know anything about the second variant. diff --git a/docs/_v0/index.md b/docs/_v0/index.md new file mode 100644 index 0000000..3b10e0d --- /dev/null +++ b/docs/_v0/index.md @@ -0,0 +1,20 @@ +--- +title: Overview +has_children: true +nav_order: 1 +permalink: /v0/ +--- + +# Schemars + +Schemars is a library to generate JSON Schema documents from Rust data structures. + +This is built on Rust's trait system - any type which implements the [`JsonSchema`](https://docs.rs/schemars/latest/schemars/trait.JsonSchema.html) trait can have a JSON Schema generated describing that type. Schemars implements this on many standard library types, and provides a derive macro to automatically implement it on custom types. + +One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/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. + +## 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. + +{% include example.md name="main" %} diff --git a/docs/docker-compose.yml b/docs/docker-compose.yml new file mode 100644 index 0000000..0afa5eb --- /dev/null +++ b/docs/docker-compose.yml @@ -0,0 +1,10 @@ +--- +services: + jekyll: + build: + context: . + volumes: + - ".:/docs" + working_dir: "/docs" + ports: + - 4000:4000 \ No newline at end of file diff --git a/docs/examples/1-derive_jsonschema.md b/docs/examples/1-derive_jsonschema.md index 3bf4548..efe245c 100644 --- a/docs/examples/1-derive_jsonschema.md +++ b/docs/examples/1-derive_jsonschema.md @@ -1,5 +1,4 @@ --- -layout: default title: Deriving JsonSchema parent: Examples nav_order: 1 diff --git a/docs/examples/2-serde_attrs.md b/docs/examples/2-serde_attrs.md index 0044a6e..79536e2 100644 --- a/docs/examples/2-serde_attrs.md +++ b/docs/examples/2-serde_attrs.md @@ -1,14 +1,13 @@ --- -layout: default title: Using Serde Attributes parent: Examples nav_order: 2 -summary: 'Deriving JsonSchema on types that use #[serde] attributes to customise serialization behaviour.' +summary: "Deriving JsonSchema on types that use #[serde] attributes to customise serialization behaviour." --- # Using Serde Attributes -One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema *should* match how [serde_json](https://github.com/serde-rs/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. +One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/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. The list of supported `#[serde]` attributes are [documented here]({{ site.baseurl }}{% link 1.1-attributes.md %}#supported-serde-attributes). diff --git a/docs/examples/3-schemars_attrs.md b/docs/examples/3-schemars_attrs.md index 5956a25..d3a2c08 100644 --- a/docs/examples/3-schemars_attrs.md +++ b/docs/examples/3-schemars_attrs.md @@ -1,9 +1,8 @@ --- -layout: default title: Using Schemars Attributes parent: Examples nav_order: 3 -summary: 'Deriving JsonSchema on types that use #[schemars] attributes to customise serialization behaviour.' +summary: "Deriving JsonSchema on types that use #[schemars] attributes to customise serialization behaviour." --- # Using Serde Attributes diff --git a/docs/examples/4-custom_settings.md b/docs/examples/4-custom_settings.md index e9482cc..7b85f65 100644 --- a/docs/examples/4-custom_settings.md +++ b/docs/examples/4-custom_settings.md @@ -1,5 +1,4 @@ --- -layout: default title: Custom Schema Settings parent: Examples nav_order: 4 diff --git a/docs/examples/5-remote_derive.md b/docs/examples/5-remote_derive.md index 93e99c1..fd7f74f 100644 --- a/docs/examples/5-remote_derive.md +++ b/docs/examples/5-remote_derive.md @@ -1,5 +1,4 @@ --- -layout: default title: Derive for Remote Crate parent: Examples nav_order: 5 diff --git a/docs/examples/6-doc_comments.md b/docs/examples/6-doc_comments.md index 9a5cdf9..66f4a49 100644 --- a/docs/examples/6-doc_comments.md +++ b/docs/examples/6-doc_comments.md @@ -1,5 +1,4 @@ --- -layout: default title: Doc Comments parent: Examples nav_order: 6 diff --git a/docs/examples/7-custom_serialization.md b/docs/examples/7-custom_serialization.md index 8caa930..b124ae7 100644 --- a/docs/examples/7-custom_serialization.md +++ b/docs/examples/7-custom_serialization.md @@ -1,5 +1,4 @@ --- -layout: default title: Custom Serialization parent: Examples nav_order: 7 @@ -13,7 +12,7 @@ summary: >- 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")]` or `#[schemars(schema_with = "path")]` attribute. +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. {% include example.md name="custom_serialization" %} diff --git a/docs/examples/8-enum_repr.md b/docs/examples/8-enum_repr.md index 0312c29..9533cba 100644 --- a/docs/examples/8-enum_repr.md +++ b/docs/examples/8-enum_repr.md @@ -1,5 +1,4 @@ --- -layout: default title: Serialize Enum as Number (serde_repr) parent: Examples nav_order: 8 diff --git a/docs/examples/9-from_value.md b/docs/examples/9-from_value.md index b711be0..8922925 100644 --- a/docs/examples/9-from_value.md +++ b/docs/examples/9-from_value.md @@ -1,5 +1,4 @@ --- -layout: default title: Generate Schema from Example Value parent: Examples nav_order: 9 diff --git a/docs/index.md b/docs/index.md index 2868342..ad71e78 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,4 @@ --- -layout: default title: Overview nav_order: 1 --- @@ -10,7 +9,7 @@ Schemars is a library to generate JSON Schema documents from Rust data structure This is built on Rust's trait system - any type which implements the [`JsonSchema`](https://docs.rs/schemars/latest/schemars/trait.JsonSchema.html) trait can have a JSON Schema generated describing that type. Schemars implements this on many standard library types, and provides a derive macro to automatically implement it on custom types. -One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema *should* match how [serde_json](https://github.com/serde-rs/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. +One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/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. ## Basic Usage