domainstack_schema/
lib.rs

1//! Schema generation for domainstack validation types.
2//!
3//! This crate provides both OpenAPI 3.0 and JSON Schema (Draft 2020-12) generation
4//! from Rust types with validation rules.
5//!
6//! # Two Approaches
7//!
8//! | Approach | OpenAPI | JSON Schema |
9//! |----------|---------|-------------|
10//! | **Trait** | `ToSchema` | `ToJsonSchema` |
11//! | **CLI** | `domainstack openapi` | `domainstack json-schema` |
12//!
13//! Use the **trait approach** for programmatic generation and type-safe composition.
14//! Use the **CLI approach** for build-time codegen from source files.
15//!
16//! # JSON Schema Quick Start
17//!
18//! ```rust
19//! use domainstack_schema::{JsonSchemaBuilder, JsonSchema, ToJsonSchema};
20//!
21//! struct User {
22//!     email: String,
23//!     age: u8,
24//! }
25//!
26//! impl ToJsonSchema for User {
27//!     fn schema_name() -> &'static str {
28//!         "User"
29//!     }
30//!
31//!     fn json_schema() -> JsonSchema {
32//!         JsonSchema::object()
33//!             .property("email", JsonSchema::string().format("email"))
34//!             .property("age", JsonSchema::integer().minimum(0).maximum(150))
35//!             .required(&["email", "age"])
36//!     }
37//! }
38//!
39//! let doc = JsonSchemaBuilder::new()
40//!     .title("My Schema")
41//!     .register::<User>()
42//!     .build();
43//! ```
44//!
45//! ---
46//!
47//! # OpenAPI Quick Start
48//!
49//! This crate provides tools to generate OpenAPI 3.0 component schemas from Rust types,
50//! with a focus on mapping validation rules to OpenAPI constraints.
51//!
52//! # Features
53//!
54//! - **Schema Composition** - anyOf, allOf, oneOf for union and inheritance patterns
55//! - **Rich Metadata** - default values, examples, deprecation markers
56//! - **Request/Response Modifiers** - readOnly, writeOnly for accurate API modeling
57//! - **Vendor Extensions** - Preserve non-mappable validations (cross-field, conditional, etc.)
58//! - **Type-Safe** - Fluent builder API with compile-time guarantees
59//! - **Framework Agnostic** - Works with any Rust web framework
60//!
61//! # Quick Start
62//!
63//! ```rust
64//! use domainstack_schema::{OpenApiBuilder, Schema, ToSchema};
65//! use serde_json::json;
66//!
67//! struct User {
68//!     email: String,
69//!     age: u8,
70//! }
71//!
72//! impl ToSchema for User {
73//!     fn schema_name() -> &'static str {
74//!         "User"
75//!     }
76//!
77//!     fn schema() -> Schema {
78//!         Schema::object()
79//!             .property("email", Schema::string().format("email"))
80//!             .property("age", Schema::integer().minimum(18).maximum(120))
81//!             .required(&["email", "age"])
82//!     }
83//! }
84//!
85//! let spec = OpenApiBuilder::new("My API", "1.0.0")
86//!     .description("User management API")
87//!     .register::<User>()
88//!     .build();
89//!
90//! let json = spec.to_json().expect("Failed to serialize");
91//! println!("{}", json);
92//! ```
93//!
94//! # Validation Rule Mapping
95//!
96//! Maps domainstack validation rules to OpenAPI constraints:
97//!
98//! | Validation | OpenAPI | Example |
99//! |------------|---------|---------|
100//! | `length(min, max)` | `minLength`, `maxLength` | `.min_length(3).max_length(50)` |
101//! | `range(min, max)` | `minimum`, `maximum` | `.minimum(0).maximum(100)` |
102//! | `email()` | `format: "email"` | `.format("email")` |
103//! | `one_of(...)` | `enum` | `.enum_values(&["a", "b"])` |
104//! | `numeric_string()` | `pattern` | `.pattern("^[0-9]+$")` |
105//! | `min_items(n)` | `minItems` | `.min_items(1)` |
106//! | `max_items(n)` | `maxItems` | `.max_items(10)` |
107//!
108//! # Schema Composition (v0.8+)
109//!
110//! ## Union Types (anyOf)
111//!
112//! ```rust
113//! use domainstack_schema::Schema;
114//!
115//! // Field can be string OR integer
116//! let flexible = Schema::any_of(vec![
117//!     Schema::string(),
118//!     Schema::integer(),
119//! ]);
120//! ```
121//!
122//! ## Inheritance (allOf)
123//!
124//! ```rust
125//! use domainstack_schema::Schema;
126//!
127//! // AdminUser extends User
128//! let admin = Schema::all_of(vec![
129//!     Schema::reference("User"),
130//!     Schema::object().property("admin", Schema::boolean()),
131//! ]);
132//! ```
133//!
134//! ## Discriminated Unions (oneOf)
135//!
136//! ```rust
137//! use domainstack_schema::Schema;
138//!
139//! let payment = Schema::one_of(vec![
140//!     Schema::object()
141//!         .property("type", Schema::string().enum_values(&["card"]))
142//!         .property("cardNumber", Schema::string()),
143//!     Schema::object()
144//!         .property("type", Schema::string().enum_values(&["cash"]))
145//!         .property("amount", Schema::number()),
146//! ]);
147//! ```
148//!
149//! # Metadata & Documentation (v0.8+)
150//!
151//! ```rust
152//! use domainstack_schema::Schema;
153//! use serde_json::json;
154//!
155//! let theme = Schema::string()
156//!     .enum_values(&["light", "dark", "auto"])
157//!     .default(json!("auto"))          // Default value
158//!     .example(json!("dark"))           // Single example
159//!     .examples(vec![                   // Multiple examples
160//!         json!("light"),
161//!         json!("dark"),
162//!     ])
163//!     .description("UI theme preference");
164//! ```
165//!
166//! # Request/Response Modifiers (v0.8+)
167//!
168//! ```rust
169//! use domainstack_schema::Schema;
170//!
171//! let user = Schema::object()
172//!     .property("id",
173//!         Schema::string()
174//!             .read_only(true)         // Response only
175//!             .description("Auto-generated ID")
176//!     )
177//!     .property("password",
178//!         Schema::string()
179//!             .write_only(true)        // Request only
180//!             .min_length(8)
181//!     )
182//!     .property("oldField",
183//!         Schema::string()
184//!             .deprecated(true)        // Mark as deprecated
185//!     );
186//! ```
187//!
188//! # Vendor Extensions (v0.8+)
189//!
190//! For validations that don't map to OpenAPI (cross-field, conditional, async):
191//!
192//! ```rust
193//! use domainstack_schema::Schema;
194//! use serde_json::json;
195//!
196//! let date_range = Schema::object()
197//!     .property("startDate", Schema::string().format("date"))
198//!     .property("endDate", Schema::string().format("date"))
199//!     .extension("x-domainstack-validations", json!({
200//!         "cross_field": ["endDate > startDate"]
201//!     }));
202//! ```
203//!
204//! # Scope & Limitations
205//!
206//! **What this crate does:**
207//! - Generates OpenAPI 3.0 component schemas for domain types
208//! - Maps field-level validations to OpenAPI constraints
209//! - Provides type-safe schema builders
210//! - Exports to JSON/YAML
211//!
212//! **What this crate does NOT do:**
213//! - API paths/operations (GET /users, POST /users, etc.)
214//! - Request/response body definitions
215//! - Security schemes or authentication
216//! - Full API documentation generation
217//!
218//! For complete API documentation, use framework adapters:
219//! - `domainstack-axum` for Axum
220//! - `domainstack-actix` for Actix-web
221//! - Or integrate with `utoipa`, `aide`, etc.
222//!
223//! # Complete Documentation
224//!
225//! See `OPENAPI_CAPABILITIES.md` for:
226//! - Complete feature matrix
227//! - Detailed examples for every feature
228//! - Workarounds for limitations
229//! - Best practices
230//! - Performance characteristics
231
232mod json_schema;
233mod openapi;
234mod schema;
235mod traits;
236
237pub use json_schema::{
238    AdditionalProperties, JsonSchema, JsonSchemaBuilder, JsonSchemaType, ToJsonSchema,
239};
240pub use openapi::{OpenApiBuilder, OpenApiSpec};
241pub use schema::{Schema, SchemaType};
242pub use traits::ToSchema;