schemars

repository·master·Indexed 23 days ago

https://github.com/gresau/schemars

A Rust library for generating JSON Schema documents from Rust code, primarily using the #[derive(JsonSchema)] procedural macro. It is designed to be compatible with serde, respecting #[serde(...)] attributes to ensure schemas match serialization behavior, while providing #[schemars(...)] attributes for schema-specific customizations. It supports generating schemas from example values via schema_for_value!, provides integration with validator and garde crates for constraints, and offers feature flags for common external crates like chrono and uuid.

Tokens
14.9K
Snippets
33
Records
86
Agent score
78%

What's inside schemars

  1. Generate JSON Schema from Rust types with Schemars

    master

    Schemars allows you to generate JSON Schema documents from Rust data structures using the JsonSchema trait. It is designed to be compatible with Serde, meaning it respects #[serde(...)] attributes to ensure the generated schema matches how serde_json would serialize or deserialize the data.

    To use it, any type you want to describe must implement the JsonSchema trait. Schemars provides implementations for many standard library types and offers a derive macro for custom types.

  2. How `Schema` changed in 1.0

    master

    In Schemars 1.0, Schema is no longer a struct with individual keyword fields. It is now a wrapper around serde_json::Value (specifically a Value::Bool or Value::Object).

    Key changes:

    • Schema is located at schemars::Schema (previously schemars::schema::Schema).
    • All types previously in the schemars::schema module have been removed.
    • Functions returning RootSchema now return Schema.
    • Use the json_schema! macro to create new Schema instances, similar to serde_json::json!.

    To modify a schema, you now interact with the underlying JSON structure directly via serde_json methods.

    use schemars::{json_schema, Schema};
    
    // Create a Schema for an object with property `foo`
    let mut schema: Schema = json_schema!({
        "type": "object",
        "properties": {
            "foo": true
        }
    });
    
    // Make the `foo` property required
    schema
        .ensure_object()
        .entry("required")
        .or_insert(serde_json::Value::Array(Vec::new()))
        .as_array_mut()
        .expect("`required` should be an array")
        .push("foo".into());
  3. Use doc comments for schema `title` and `description`

    master

    Schemars automatically converts Rust doc comments (/// or #[doc = "..."]) into schema metadata:

    1. Description: All doc comments are used as the schema's description.
    2. Title: If the first line of the doc comment is an ATX-style markdown heading (starting with #), it is used as the schema's title, and the subsequent lines are used as the description.
  4. Custom schema generation with `SchemaSettings` and `SchemaGenerator`

    master

    For advanced control over schema generation, use the gen module instead of the basic macro. The module provides two primary components:

    • SchemaSettings: Defines which JSON Schema features are used during generation (e.g., how Option types are represented).
    • SchemaGenerator: Manages the actual generation process of a schema document.
  5. Use doc comments for schema descriptions and titles

    master

    Schemars can automatically derive schema metadata from Rust doc comments (/// or #[doc = "..."]):

    • Description: All lines in the doc comment are used as the description.
    • Title: If the first line of the doc comment is an ATX-style markdown heading (starts with #), it is used as the schema's title, and the remaining lines become the description.
  6. Customize JsonSchema with Attributes

    master

    You can customize the derived JsonSchema implementation by adding attributes to your types.

    Schemars generally respects #[serde(...)] attributes to ensure generated schemas match how types are serialized by serde_json. However, you can override these using #[schemars(...)] attributes if you want to change the schema without affecting Serde's behavior, or if you are not using Serde at all.

    To "unset" a Serde attribute so that Schemars ignores it, use the attribute with a ! prefix inside a #[schemars(...)] block.

    #[derive(Deserialize, Serialize, JsonSchema)]
    #[serde(from = "OtherType")]
    // this makes schemars ignore the `from = "OtherType"` from the serde attribute:
    #[schemars(!from)]
    pub struct MyStruct {
        // ...
    }
  7. Ensure JSON Schema compatibility with Serde attributes

    master

    Schemars is designed to be compatible with serde. It automatically detects and respects #[serde(...)] attributes (like rename, rename_all, deny_unknown_fields, default, or untagged) when generating schemas. This ensures the generated JSON schema matches how serde_json would actually serialize or deserialize the data.

    If you want to modify the generated schema without changing how Serde behaves, you can use #[schemars(...)] attributes, which behave identically to Serde attributes but only affect the schema generation.

    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());
  8. Configure schema to describe serialization behavior

    master
    By default, Schemars generates schemas based on the Deserialize contract (how types are read). To generate a schema that describes how types are serialized (the Serialize contract), you must modify the contract field in SchemaSettings or use the for_serialize() helper method.
  9. Customize JsonSchema using Serde attributes

    master
    Schemars respects #[serde(...)] attributes to ensure generated schemas match how types are serialized by serde_json. You can override these behaviors using #[schemars(...)] attributes if you want to change the schema without affecting Serde's serialization behavior, or if you are not using Serde at all.
  10. Derive JsonSchema for a type in a different crate

    master

    Due to Rust's orphan rules, you cannot directly implement JsonSchema for a type defined in an external crate. To work around this, Schemars supports a "remote derive" pattern.

    To use this pattern, you must define a local "shadow" version of the remote type that mirrors its structure. You then apply #[derive(JsonSchema)] to this local type and use the #[schemars(remote = "...")] attribute to link it to the original remote type. This allows Schemars to generate a schema for the remote type by processing your local definition.

  11. Customize JSON Schema generation with #[schemars] attributes

    master
    You can use #[schemars(...)] attributes to override or replace #[serde(...)] attributes when deriving JsonSchema. This is useful when you want to modify the generated JSON Schema (e.g., changing field descriptions, constraints, or visibility) without altering how the type is serialized or deserialized by Serde. This also allows you to customize schemas for types that do not use Serde at all.
  12. Set custom schema titles and descriptions using doc comments

    master

    Schemars can automatically extract metadata for your JSON schemas from Rust doc comments (///) or #[doc = "..."] attributes.

    • Description: Any doc comments attached to a struct, enum variant, or field will be used as the generated schema's description field.
    • Title: If the first line of the doc comment is an ATX-style markdown heading (starting with #), that line will be used as the schema's title, and all subsequent lines will be used as the description.