user_api/
user_api.rs

1//! Complete example of OpenAPI schema generation for a User API.
2//!
3//! This example demonstrates how to:
4//! 1. Define domain types with validation
5//! 2. Implement ToSchema to generate OpenAPI schemas
6//! 3. Map validation rules to OpenAPI constraints
7//! 4. Build a complete OpenAPI specification
8
9use domainstack_schema::{OpenApiBuilder, Schema, ToSchema};
10
11// Domain type (validation can be manual or via derive)
12#[allow(dead_code)]
13struct User {
14    email: String,
15    age: u8,
16    name: String,
17    status: String,
18}
19
20// Manual ToSchema implementation that mirrors validation rules
21impl ToSchema for User {
22    fn schema_name() -> &'static str {
23        "User"
24    }
25
26    fn schema() -> Schema {
27        Schema::object()
28            .description("User account")
29            .property(
30                "email",
31                Schema::string()
32                    .format("email")
33                    .description("User email address"),
34            )
35            .property(
36                "age",
37                Schema::integer()
38                    .minimum(18)
39                    .maximum(120)
40                    .description("User age (18-120)"),
41            )
42            .property(
43                "name",
44                Schema::string()
45                    .min_length(3)
46                    .max_length(50)
47                    .description("User full name"),
48            )
49            .property(
50                "status",
51                Schema::string()
52                    .enum_values(&["active", "pending", "inactive"])
53                    .description("User account status"),
54            )
55            .required(&["email", "age", "name", "status"])
56    }
57}
58
59#[allow(dead_code)]
60struct Address {
61    street: String,
62    zip_code: String,
63    city: String,
64}
65
66impl ToSchema for Address {
67    fn schema_name() -> &'static str {
68        "Address"
69    }
70
71    fn schema() -> Schema {
72        Schema::object()
73            .description("Physical address")
74            .property(
75                "street",
76                Schema::string()
77                    .min_length(1)
78                    .max_length(100)
79                    .description("Street address"),
80            )
81            .property(
82                "zipCode",
83                Schema::string()
84                    .min_length(5)
85                    .max_length(5)
86                    .pattern("^[0-9]{5}$")
87                    .description("5-digit ZIP code"),
88            )
89            .property(
90                "city",
91                Schema::string()
92                    .min_length(2)
93                    .max_length(50)
94                    .description("City name"),
95            )
96            .required(&["street", "zipCode", "city"])
97    }
98}
99
100#[allow(dead_code)]
101struct Team {
102    name: String,
103    members: Vec<String>, // Simplified - would be Vec<User> in real app
104}
105
106impl ToSchema for Team {
107    fn schema_name() -> &'static str {
108        "Team"
109    }
110
111    fn schema() -> Schema {
112        Schema::object()
113            .description("Team of users")
114            .property(
115                "name",
116                Schema::string()
117                    .min_length(1)
118                    .max_length(50)
119                    .description("Team name"),
120            )
121            .property(
122                "members",
123                Schema::array(Schema::reference("User"))
124                    .min_items(1)
125                    .max_items(10)
126                    .description("Team members (1-10 users)"),
127            )
128            .required(&["name", "members"])
129    }
130}
131
132fn main() {
133    // Build OpenAPI specification
134    let spec = OpenApiBuilder::new("User Management API", "1.0.0")
135        .description("API for managing users, addresses, and teams with validation")
136        .register::<User>()
137        .register::<Address>()
138        .register::<Team>()
139        .build();
140
141    // Output as JSON
142    let json = spec.to_json().expect("Failed to serialize to JSON");
143    println!("{}", json);
144
145    println!("\n=== Schema Generation Complete ===");
146    println!("Registered schemas:");
147    println!("  - User (with email, age, name, status)");
148    println!("  - Address (with street, zip code, city)");
149    println!("  - Team (with name and members array)");
150    println!("\nValidation constraints mapped to OpenAPI:");
151    println!("  [ok] email → format: email");
152    println!("  [ok] range(min, max) → minimum, maximum");
153    println!("  [ok] length(min, max) → minLength, maxLength");
154    println!("  [ok] one_of → enum");
155    println!("  [ok] min_items, max_items → minItems, maxItems");
156    println!("  [ok] numeric_string → pattern: ^[0-9]+$");
157}