domainstack
Full-stack validation ecosystem for Rust web services
Define validation once. Get runtime checks, OpenAPI schemas, TypeScript types, and framework integration—from one source of truth.
Rust Domain Frontend
| |
#[derive(Validate, ToSchema)] domainstack zod
| |
v v
.validate()? Zod schemas
| |
v v
Axum / Actix / Rocket <------> Same rules,
| both sides
v
Structured errors (field-level, indexed paths)
Progressive adoption — use what you need:
| Need | Start With |
|---|---|
| Just validation | domainstack core |
| + derive macros | + domainstack-derive |
| + OpenAPI schemas | + domainstack-schema |
| + Axum/Actix/Rocket | + framework adapter |
| + TypeScript/Zod | + domainstack-cli |
Why domainstack?
domainstack turns untrusted input into valid-by-construction domain objects with stable, field-level errors your APIs and UIs can depend on.
Built for the boundary you actually live at:
HTTP/JSON → DTOs → Domain (validated) → Business logic
Two validation gates
Gate 1: Serde (decode + shape) — JSON → DTO. Fails on invalid JSON, type mismatches, missing required fields.
Gate 2: Domain (construct + validate) — DTO → Domain. Produces structured field-level errors your APIs depend on.
After domain validation succeeds, you can optionally run async/context validation (DB/API checks like uniqueness, rate limits, authorization) as a post-validation phase.
vs. validator/garde
validator and garde focus on: "Is this struct valid?"
domainstack focuses on the full ecosystem:
- DTO → Domain conversion with field-level error paths
- Rules as composable values (
.and(),.or(),.when()) - Async validation with context (DB checks, API calls)
- Framework adapters that map errors to structured HTTP responses
- OpenAPI schemas generated from the same validation rules
- TypeScript/Zod codegen for frontend parity
If you want valid-by-construction domain types with errors that map cleanly to forms and clients, domainstack is purpose-built for that.
What that gives you
- Domain-first modeling: make invalid states difficult (or impossible) to represent
- Composable rule algebra: reusable rules with
.and(),.or(),.when() - Structured error paths:
rooms[0].adults,guest.email.value(UI-friendly) - Cross-field validation: invariants like password confirmation, date ranges
- Type-state tracking: phantom types to enforce "validated" at compile time
- Schema + client parity: generate OpenAPI (and TypeScript/Zod via CLI) from the same Rust rules
- Framework adapters: one-line boundary extraction (Axum / Actix / Rocket)
- Lean core: zero-deps base, opt-in features for regex / async / chrono / serde
Table of Contents
- Quick Start
- Installation
- Key Features
- Examples
- Framework Adapters
- Running Examples
- Crates
- Documentation
- License
- Contributing
Quick Start
Dependencies (add to Cargo.toml):
[]
= { = "1.0", = ["derive", "regex", "chrono"] }
= "1.0"
= "1.0" # Or domainstack-actix if using Actix-web
= { = "1", = ["derive"] }
= "0.4"
= "0.7"
Complete example (with all imports):
use Json;
use NaiveDate;
use *;
use ;
use ;
use Deserialize;
// DTO from HTTP/JSON (untrusted input)
// Domain models with validation rules (invalid states impossible)
// TryFrom: DTO → Domain conversion with validation
// Axum handler: one-line extraction with automatic validation
type BookingJson = ;
async
On validation failure, automatic structured errors:
Auto-generated TypeScript/Zod from the same Rust code:
// Zero duplication - generated from Rust validation rules!
export const bookingSchema = z.object({
guest_email: z.string().email().max(255),
check_in: z.string(),
check_out: z.string(),
rooms: z.array(z.object({
adults: z.number().min(1).max(4),
children: z.number().min(0).max(3)
})).min(1).max(5)
}).refine(
(data) => data.check_in < data.check_out,
{ message: "Check-out must be after check-in" }
);
Installation
[]
= { = "1.0", = ["derive", "regex"] }
= "1.0" # or domainstack-actix, domainstack-rocket
# Optional
= "1.0" # OpenAPI generation
For complete installation guide, feature flags, and companion crates, see INSTALLATION.md
Key Features
- 37 Validation Rules - String, numeric, collection, and date/time validation → RULES.md
- Derive Macros -
#[derive(Validate)]for declarative validation → DERIVE_MACRO.md - Composable Rules -
.and(),.or(),.when()combinators for complex logic - Nested Validation - Automatic path tracking for deeply nested structures
- Collection Validation - Array indices in error paths (
items[0].field) - Serde Integration - Validate during deserialization → SERDE_INTEGRATION.md
- Async Validation - Database/API checks with
AsyncValidate→ ASYNC_VALIDATION.md - Cross-Field Validation - Password confirmation, date ranges → CROSS_FIELD_VALIDATION.md
- Type-State Validation - Compile-time guarantees with phantom types → TYPE_STATE.md
- OpenAPI Schema Generation - Auto-generate schemas from rules → OPENAPI_SCHEMA.md
- JSON Schema Generation - Draft 2020-12 schemas from validation rules → CLI_GUIDE.md
- Framework Adapters - Axum, Actix-web, Rocket extractors → HTTP_INTEGRATION.md
Examples
Derive Macro (Recommended)
Most validation is declarative with #[derive(Validate)]:
// Validate all fields at once
let user = User ;
user.validate?; // [ok] Validates all constraints
See the examples folder for more:
- Nested validation with path tracking
- Collection item validation
- Manual validation for newtypes
- Cross-field validation
- Async validation
- Type-state patterns
- OpenAPI schema generation
- Framework integration examples
Framework Adapters
One-line DTO→Domain extractors with automatic validation and structured error responses:
| Framework | Crate | Extractor |
|---|---|---|
| Axum | domainstack-axum |
DomainJson<T, Dto> |
| Actix-web | domainstack-actix |
DomainJson<T, Dto> |
| Rocket | domainstack-rocket |
DomainJson<T, Dto> |
Running Examples
See examples/README.md for instructions on running all examples.
Crates
8 publishable crates for modular adoption:
| Category | Crates |
|---|---|
| Core | domainstack, domainstack-derive, domainstack-schema, domainstack-envelope |
| Web Framework Integrations | domainstack-axum, domainstack-actix, domainstack-rocket, domainstack-http |
4 example crates (repository only): domainstack-examples, examples-axum, examples-actix, examples-rocket
Complete Crate List - Detailed descriptions and links
Documentation
| Getting Started | |
| Core Concepts | Valid-by-construction types, error paths |
| Domain Modeling | DTO→Domain, smart constructors |
| Installation | Feature flags, companion crates |
| Guides | |
| Derive Macro | #[derive(Validate)] reference |
| Validation Rules | All 37 built-in rules |
| Error Handling | Violations, paths, i18n |
| HTTP Integration | Axum / Actix / Rocket |
| Advanced | |
| Async Validation | DB/API checks, context |
| OpenAPI Schema | Generate from rules |
| CLI / Zod / JSON Schema | TypeScript and JSON Schema codegen |
| Serde Integration | Validate on deserialize |
Reference: API Docs · Architecture · Examples
License
Apache 2.0
Author
Dayna Blackwell - blackwellsystems@protonmail.com
Contributing
This is an early-stage project. Issues and pull requests are welcome!