Schema

Struct Schema 

Source
pub struct Schema;
Expand description

Entry point for creating validation schemas.

Schema provides factory methods for creating different schema types. Each schema type validates specific value types and supports various constraints through a builder pattern.

§Example

use postmortem::Schema;

// Create a string schema with length constraints
let string_schema = Schema::string()
    .min_len(1)
    .max_len(100);

// Create a string schema with pattern validation
let email_schema = Schema::string()
    .pattern(r"@")
    .unwrap()
    .error("must contain @");

Implementations§

Source§

impl Schema

Source

pub fn string() -> StringSchema

Creates a new string schema.

The returned schema validates that values are strings. Use builder methods to add constraints like minimum/maximum length or patterns.

§Example
use postmortem::{Schema, JsonPath};
use serde_json::json;

let schema = Schema::string().min_len(5);

let result = schema.validate(&json!("hello"), &JsonPath::root());
assert!(result.is_success());

let result = schema.validate(&json!("hi"), &JsonPath::root());
assert!(result.is_failure());
Source

pub fn integer() -> IntegerSchema

Creates a new integer schema.

The returned schema validates that values are integers (not floats). Use builder methods to add constraints like minimum/maximum value, range, or sign requirements.

§Example
use postmortem::{Schema, JsonPath};
use serde_json::json;

let schema = Schema::integer().min(0).max(100);

let result = schema.validate(&json!(50), &JsonPath::root());
assert!(result.is_success());

let result = schema.validate(&json!(-5), &JsonPath::root());
assert!(result.is_failure());

// Float values are rejected
let result = schema.validate(&json!(1.5), &JsonPath::root());
assert!(result.is_failure());
Source

pub fn object() -> ObjectSchema

Creates a new object schema.

The returned schema validates that values are JSON objects. Use builder methods to define required fields, optional fields, default values, and control handling of additional properties.

§Example
use postmortem::{Schema, JsonPath};
use serde_json::json;

let schema = Schema::object()
    .field("name", Schema::string().min_len(1))
    .field("age", Schema::integer().positive())
    .optional("email", Schema::string())
    .default("role", Schema::string(), json!("user"))
    .additional_properties(false);

let result = schema.validate(&json!({
    "name": "Alice",
    "age": 30
}), &JsonPath::root());
assert!(result.is_success());

// Missing required field produces error
let result = schema.validate(&json!({"name": "Bob"}), &JsonPath::root());
assert!(result.is_failure());
Source

pub fn array<S: SchemaLike>(item_schema: S) -> ArraySchema<S>

Creates a new array schema with the given item schema.

The returned schema validates that values are arrays and that each item passes validation against the provided item schema. Use builder methods to add constraints like minimum/maximum length or uniqueness.

§Example
use postmortem::{Schema, JsonPath};
use serde_json::json;

// Array of positive integers
let schema = Schema::array(Schema::integer().positive())
    .min_len(1)
    .max_len(10);

let result = schema.validate(&json!([1, 2, 3]), &JsonPath::root());
assert!(result.is_success());

// Empty array fails min_len constraint
let result = schema.validate(&json!([]), &JsonPath::root());
assert!(result.is_failure());

// Non-positive integer fails item validation
let result = schema.validate(&json!([1, -2, 3]), &JsonPath::root());
assert!(result.is_failure());
Source

pub fn one_of<I>(schemas: I) -> CombinatorSchema
where I: IntoIterator<Item = Box<dyn ValueValidator>>,

Creates a one-of combinator schema.

Exactly one of the provided schemas must match. This is ideal for discriminated unions where a value must be one of several distinct types.

§Example
use postmortem::{Schema, ValueValidator, SchemaLike, JsonPath};
use serde_json::json;

// Shape can be either a circle or rectangle
let shape = Schema::one_of(vec![
    Box::new(Schema::object()
        .field("type", Schema::string())
        .field("radius", Schema::integer().positive())) as Box<dyn ValueValidator>,
    Box::new(Schema::object()
        .field("type", Schema::string())
        .field("width", Schema::integer().positive())
        .field("height", Schema::integer().positive())) as Box<dyn ValueValidator>,
]);

let result = shape.validate(&json!({
    "type": "circle",
    "radius": 5
}), &JsonPath::root());
assert!(result.is_success());
Source

pub fn any_of<I>(schemas: I) -> CombinatorSchema
where I: IntoIterator<Item = Box<dyn ValueValidator>>,

Creates an any-of combinator schema.

At least one of the provided schemas must match. This is more permissive than one_of and allows multiple matches. Validation short-circuits on the first match.

§Example
use postmortem::{Schema, ValueValidator, SchemaLike, JsonPath};
use serde_json::json;

// ID can be either a string or positive integer
let id = Schema::any_of(vec![
    Box::new(Schema::string().min_len(1)) as Box<dyn ValueValidator>,
    Box::new(Schema::integer().positive()) as Box<dyn ValueValidator>,
]);

let result = id.validate(&json!("abc-123"), &JsonPath::root());
assert!(result.is_success());

let result = id.validate(&json!(42), &JsonPath::root());
assert!(result.is_success());
Source

pub fn all_of<I>(schemas: I) -> CombinatorSchema
where I: IntoIterator<Item = Box<dyn ValueValidator>>,

Creates an all-of combinator schema.

All of the provided schemas must match. This is useful for schema composition and intersection, where a value must satisfy multiple independent constraints.

§Example
use postmortem::{Schema, ValueValidator, SchemaLike, JsonPath};
use serde_json::json;

// Entity must have both a name and a timestamp
let named = Schema::object()
    .field("name", Schema::string().min_len(1));

let timestamped = Schema::object()
    .field("created_at", Schema::string());

let entity = Schema::all_of(vec![
    Box::new(named) as Box<dyn ValueValidator>,
    Box::new(timestamped) as Box<dyn ValueValidator>,
]);

let result = entity.validate(&json!({
    "name": "Alice",
    "created_at": "2025-01-01"
}), &JsonPath::root());
assert!(result.is_success());
Source

pub fn optional(inner: Box<dyn ValueValidator>) -> CombinatorSchema

Creates an optional combinator schema.

The value can be null. Non-null values are validated against the inner schema.

§Example
use postmortem::{Schema, ValueValidator, SchemaLike, JsonPath};
use serde_json::json;

let optional_string = Schema::optional(
    Box::new(Schema::string().min_len(1)) as Box<dyn ValueValidator>
);

// Null is valid
let result = optional_string.validate(&json!(null), &JsonPath::root());
assert!(result.is_success());

// Non-null values are validated
let result = optional_string.validate(&json!("hello"), &JsonPath::root());
assert!(result.is_success());

let result = optional_string.validate(&json!(""), &JsonPath::root());
assert!(result.is_failure());
Source

pub fn ref_(name: impl Into<String>) -> RefSchema

Creates a reference to a named schema.

Schema references enable reuse and recursive structures. The referenced schema must be registered in a SchemaRegistry before validation.

References can only be validated through a registry. Attempting to validate without a registry produces an error with code missing_registry.

§Example
use postmortem::{Schema, SchemaRegistry};
use serde_json::json;

let registry = SchemaRegistry::new();

// Register base schema
registry.register("UserId", Schema::integer().positive()).unwrap();

// Use reference in another schema
registry.register("User", Schema::object()
    .field("id", Schema::ref_("UserId"))
    .field("name", Schema::string())
).unwrap();

let result = registry.validate("User", &json!({
    "id": 42,
    "name": "Alice"
})).unwrap();

assert!(result.is_success());

Auto Trait Implementations§

§

impl Freeze for Schema

§

impl RefUnwindSafe for Schema

§

impl Send for Schema

§

impl Sync for Schema

§

impl Unpin for Schema

§

impl UnwindSafe for Schema

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.