ObjectSchema

Struct ObjectSchema 

Source
pub struct ObjectSchema { /* private fields */ }
Expand description

A schema for validating JSON objects.

ObjectSchema validates that values are objects and optionally applies constraints like required fields, optional fields with defaults, and additional property handling. All field validation errors are accumulated rather than short-circuiting on the first failure.

§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())
    .additional_properties(false);

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

Implementations§

Source§

impl ObjectSchema

Source

pub fn new() -> Self

Creates a new object schema with no fields.

Source

pub fn field<S>(self, name: impl Into<String>, schema: S) -> Self
where S: SchemaLike + 'static,

Adds a required field to the schema.

The field must be present in the input object and its value must pass validation against the provided schema.

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

let schema = Schema::object()
    .field("name", Schema::string().min_len(1));

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

pub fn optional<S>(self, name: impl Into<String>, schema: S) -> Self
where S: SchemaLike + 'static,

Adds an optional field to the schema.

The field may be absent from the input object. If present, its value must pass validation against the provided schema.

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

let schema = Schema::object()
    .optional("nickname", Schema::string());

// Missing optional field is OK
let result = schema.validate(&json!({}), &JsonPath::root());
assert!(result.is_success());
Source

pub fn default<S>( self, name: impl Into<String>, schema: S, default: Value, ) -> Self
where S: SchemaLike + 'static,

Adds an optional field with a default value.

If the field is absent from the input object, the default value is used. If present, its value must pass validation against the provided schema.

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

let schema = Schema::object()
    .default("role", Schema::string(), json!("user"));

let result = schema.validate(&json!({}), &JsonPath::root());
assert!(result.is_success());
// The validated object will include "role": "user"
Source

pub fn additional_properties<S>(self, setting: S) -> Self
where S: Into<AdditionalPropertiesSetting>,

Configures how unknown properties are handled.

By default, unknown properties are allowed. Use this method to reject unknown properties or validate them against a schema.

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

// Reject unknown properties
let strict = Schema::object()
    .field("name", Schema::string())
    .additional_properties(false);

let result = strict.validate(&json!({
    "name": "Alice",
    "unknown": "field"
}), &JsonPath::root());
assert!(result.is_failure());

// Validate unknown properties against a schema
let validated = Schema::object()
    .field("name", Schema::string())
    .additional_properties(Schema::string());
Source

pub fn error(self, message: impl Into<String>) -> Self

Sets a custom error message for type errors.

This message is used when the input value is not an object.

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

let schema = Schema::object()
    .error("must be a user object");

let result = schema.validate(&json!("not an object"), &JsonPath::root());
// Error message will be "must be a user object"
Source

pub fn custom<F>(self, validator: F) -> Self
where F: Fn(&ValidatedObject, &JsonPath) -> Validation<(), SchemaErrors> + Send + Sync + 'static,

Adds a custom cross-field validator.

Cross-field validators run after all field-level validations pass (or fail, depending on skip_on_field_errors configuration). They receive a ValidatedObject containing all validated field values.

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

let schema = Schema::object()
    .field("quantity", Schema::integer().positive())
    .field("unit_price", Schema::integer().non_negative())
    .field("total", Schema::integer().non_negative())
    .custom(|obj, path| {
        let qty = obj.get("quantity").and_then(|v| v.as_i64()).unwrap_or(0);
        let price = obj.get("unit_price").and_then(|v| v.as_i64()).unwrap_or(0);
        let total = obj.get("total").and_then(|v| v.as_i64()).unwrap_or(0);

        if qty * price != total {
            Validation::Failure(postmortem::SchemaErrors::single(
                postmortem::SchemaError::new(
                    path.push_field("total"),
                    "total must equal quantity * unit_price"
                ).with_code("invalid_total")
            ))
        } else {
            Validation::Success(())
        }
    });
Source

pub fn skip_cross_field_on_errors(self, skip: bool) -> Self

Configure whether to skip cross-field validation if field validation fails.

Default: true (skip cross-field when fields are invalid).

When true, cross-field validators only run if all field-level validations pass. This is usually the desired behavior since cross-field validators often assume fields have valid values.

Set to false to always run cross-field validators, even if some field validations failed.

§Example
use postmortem::Schema;

let schema = Schema::object()
    .field("name", Schema::string())
    .skip_cross_field_on_errors(false);  // Always run cross-field validators
Source

pub fn require_if<P>( self, condition_field: impl Into<String>, predicate: P, required_field: impl Into<String>, ) -> Self
where P: Fn(&Value) -> bool + Send + Sync + 'static,

Requires a field when a condition is met.

If the condition field matches the predicate, the required field must be present.

§Example
use postmortem::Schema;
use serde_json::json;

let schema = Schema::object()
    .field("method", Schema::string())
    .optional("card_number", Schema::string())
    .require_if("method", |v| v == &json!("card"), "card_number");
Source

pub fn mutually_exclusive( self, field1: impl Into<String>, field2: impl Into<String>, ) -> Self

Ensures two fields are mutually exclusive.

At most one of the two fields can be present (non-null).

§Example
use postmortem::Schema;

let schema = Schema::object()
    .optional("email", Schema::string())
    .optional("phone", Schema::string())
    .mutually_exclusive("email", "phone");
Source

pub fn at_least_one_of<I, S>(self, fields: I) -> Self
where I: IntoIterator<Item = S>, S: Into<String>,

Requires at least one of the specified fields to be present.

At least one field must exist and be non-null.

§Example
use postmortem::Schema;

let schema = Schema::object()
    .optional("email", Schema::string())
    .optional("phone", Schema::string())
    .at_least_one_of(["email", "phone"]);
Source

pub fn equal_fields( self, field1: impl Into<String>, field2: impl Into<String>, ) -> Self

Ensures two fields have equal values.

If both fields are present, their values must be equal.

§Example
use postmortem::Schema;

let schema = Schema::object()
    .field("password", Schema::string())
    .field("confirm_password", Schema::string())
    .equal_fields("password", "confirm_password");
Source

pub fn field_less_than( self, field1: impl Into<String>, field2: impl Into<String>, ) -> Self

Ensures field1 is less than field2.

Works for numbers and strings (lexicographic comparison). Skips validation if fields are missing, null, or have incompatible types.

§Example
use postmortem::Schema;

let schema = Schema::object()
    .field("start_date", Schema::string())
    .field("end_date", Schema::string())
    .field_less_than("start_date", "end_date");
Source

pub fn field_less_or_equal( self, field1: impl Into<String>, field2: impl Into<String>, ) -> Self

Ensures field1 is less than or equal to field2.

Works for numbers and strings (lexicographic comparison). Skips validation if fields are missing, null, or have incompatible types.

§Example
use postmortem::Schema;

let schema = Schema::object()
    .field("min", Schema::integer())
    .field("max", Schema::integer())
    .field_less_or_equal("min", "max");
Source

pub fn validate( &self, value: &Value, path: &JsonPath, ) -> Validation<Map<String, Value>, SchemaErrors>

Validates a value against this schema.

Returns Validation::Success with a Map<String, Value> containing the validated fields if all validations pass, or Validation::Failure with accumulated errors if any validations fail.

Trait Implementations§

Source§

impl Default for ObjectSchema

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl SchemaLike for ObjectSchema

Source§

type Output = Map<String, Value>

The output type produced by successful validation.
Source§

fn validate( &self, value: &Value, path: &JsonPath, ) -> Validation<Self::Output, SchemaErrors>

Validates a value against this schema. Read more
Source§

fn validate_to_value( &self, value: &Value, path: &JsonPath, ) -> Validation<Value, SchemaErrors>

Validates a value and returns the result as a serde_json::Value. Read more
Source§

fn validate_with_context( &self, value: &Value, path: &JsonPath, context: &ValidationContext, ) -> Validation<Self::Output, SchemaErrors>

Validates a value with registry context for schema reference resolution. Read more
Source§

fn validate_to_value_with_context( &self, value: &Value, path: &JsonPath, context: &ValidationContext, ) -> Validation<Value, SchemaErrors>

Validates a value with context and returns the result as a serde_json::Value. Read more
Source§

fn collect_refs(&self, refs: &mut Vec<String>)

Collects all schema reference names used by this schema. Read more

Auto Trait Implementations§

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.
Source§

impl<S> ValueValidator for S
where S: SchemaLike,

Source§

fn validate_value( &self, value: &Value, path: &JsonPath, ) -> Validation<Value, SchemaErrors>

Validates a value and returns the result as a serde_json::Value.
Source§

fn validate_value_with_context( &self, value: &Value, path: &JsonPath, context: &ValidationContext, ) -> Validation<Value, SchemaErrors>

Validates a value with context and returns the result as a serde_json::Value. Read more
Source§

fn collect_refs(&self, refs: &mut Vec<String>)

Collects schema reference names. Read more