Schema

Struct Schema 

Source
pub struct Schema {
Show 27 fields pub schema_type: Option<SchemaType>, pub format: Option<String>, pub description: Option<String>, pub properties: Option<HashMap<String, Schema>>, pub required: Option<Vec<String>>, pub items: Option<Box<Schema>>, pub min_length: Option<usize>, pub max_length: Option<usize>, pub pattern: Option<String>, pub minimum: Option<f64>, pub maximum: Option<f64>, pub multiple_of: Option<f64>, pub min_items: Option<usize>, pub max_items: Option<usize>, pub unique_items: Option<bool>, pub enum: Option<Vec<Value>>, pub reference: Option<String>, pub any_of: Option<Vec<Schema>>, pub all_of: Option<Vec<Schema>>, pub one_of: Option<Vec<Schema>>, pub default: Option<Value>, pub example: Option<Value>, pub examples: Option<Vec<Value>>, pub read_only: Option<bool>, pub write_only: Option<bool>, pub deprecated: Option<bool>, pub extensions: Option<HashMap<String, Value>>,
}
Expand description

OpenAPI schema object representing a data type.

Fields§

§schema_type: Option<SchemaType>§format: Option<String>§description: Option<String>§properties: Option<HashMap<String, Schema>>§required: Option<Vec<String>>§items: Option<Box<Schema>>§min_length: Option<usize>§max_length: Option<usize>§pattern: Option<String>§minimum: Option<f64>§maximum: Option<f64>§multiple_of: Option<f64>§min_items: Option<usize>§max_items: Option<usize>§unique_items: Option<bool>§enum: Option<Vec<Value>>§reference: Option<String>§any_of: Option<Vec<Schema>>§all_of: Option<Vec<Schema>>§one_of: Option<Vec<Schema>>§default: Option<Value>§example: Option<Value>§examples: Option<Vec<Value>>§read_only: Option<bool>§write_only: Option<bool>§deprecated: Option<bool>§extensions: Option<HashMap<String, Value>>

Implementations§

Source§

impl Schema

Source

pub fn new() -> Self

Create a new empty schema.

Source

pub fn string() -> Self

Create a string schema.

Examples found in repository?
examples/v08_features.rs (line 28)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
221}
222
223// === User type for allOf example ===
224
225#[allow(dead_code)]
226struct User {
227    email: String,
228    name: String,
229}
230
231impl ToSchema for User {
232    fn schema_name() -> &'static str {
233        "User"
234    }
235
236    fn schema() -> Schema {
237        Schema::object()
238            .property("email", Schema::string().format("email"))
239            .property("name", Schema::string().min_length(1))
240            .required(&["email", "name"])
241    }
More examples
Hide additional examples
examples/user_api.rs (line 31)
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    }
Source

pub fn integer() -> Self

Create an integer schema.

Examples found in repository?
examples/user_api.rs (line 37)
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    }
Source

pub fn number() -> Self

Create a number schema.

Examples found in repository?
examples/v08_features.rs (line 34)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
Source

pub fn boolean() -> Self

Create a boolean schema.

Examples found in repository?
examples/v08_features.rs (line 56)
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
Source

pub fn array(items: Schema) -> Self

Create an array schema.

Examples found in repository?
examples/v08_features.rs (line 57)
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
More examples
Hide additional examples
examples/user_api.rs (line 123)
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    }
Source

pub fn object() -> Self

Create an object schema.

Examples found in repository?
examples/v08_features.rs (line 27)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
221}
222
223// === User type for allOf example ===
224
225#[allow(dead_code)]
226struct User {
227    email: String,
228    name: String,
229}
230
231impl ToSchema for User {
232    fn schema_name() -> &'static str {
233        "User"
234    }
235
236    fn schema() -> Schema {
237        Schema::object()
238            .property("email", Schema::string().format("email"))
239            .property("name", Schema::string().min_length(1))
240            .required(&["email", "name"])
241    }
More examples
Hide additional examples
examples/user_api.rs (line 27)
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    }
Source

pub fn reference(name: &str) -> Self

Create a reference to another schema.

Examples found in repository?
examples/v08_features.rs (line 54)
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
More examples
Hide additional examples
examples/user_api.rs (line 123)
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    }
Source

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

Set the format (e.g., “email”, “date-time”).

Examples found in repository?
examples/user_api.rs (line 32)
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    }
More examples
Hide additional examples
examples/v08_features.rs (line 133)
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
221}
222
223// === User type for allOf example ===
224
225#[allow(dead_code)]
226struct User {
227    email: String,
228    name: String,
229}
230
231impl ToSchema for User {
232    fn schema_name() -> &'static str {
233        "User"
234    }
235
236    fn schema() -> Schema {
237        Schema::object()
238            .property("email", Schema::string().format("email"))
239            .property("name", Schema::string().min_length(1))
240            .required(&["email", "name"])
241    }
Source

pub fn description(self, desc: impl Into<String>) -> Self

Set the description.

Examples found in repository?
examples/v08_features.rs (line 60)
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
More examples
Hide additional examples
examples/user_api.rs (line 28)
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    }
Source

pub fn property(self, name: impl Into<String>, schema: Schema) -> Self

Add a property to an object schema.

Examples found in repository?
examples/v08_features.rs (line 28)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
221}
222
223// === User type for allOf example ===
224
225#[allow(dead_code)]
226struct User {
227    email: String,
228    name: String,
229}
230
231impl ToSchema for User {
232    fn schema_name() -> &'static str {
233        "User"
234    }
235
236    fn schema() -> Schema {
237        Schema::object()
238            .property("email", Schema::string().format("email"))
239            .property("name", Schema::string().min_length(1))
240            .required(&["email", "name"])
241    }
More examples
Hide additional examples
examples/user_api.rs (lines 29-34)
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    }
Source

pub fn required(self, fields: &[&str]) -> Self

Set required fields.

Examples found in repository?
examples/v08_features.rs (line 31)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
221}
222
223// === User type for allOf example ===
224
225#[allow(dead_code)]
226struct User {
227    email: String,
228    name: String,
229}
230
231impl ToSchema for User {
232    fn schema_name() -> &'static str {
233        "User"
234    }
235
236    fn schema() -> Schema {
237        Schema::object()
238            .property("email", Schema::string().format("email"))
239            .property("name", Schema::string().min_length(1))
240            .required(&["email", "name"])
241    }
More examples
Hide additional examples
examples/user_api.rs (line 55)
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    }
Source

pub fn min_length(self, min: usize) -> Self

Set minimum length for strings.

Examples found in repository?
examples/v08_features.rs (line 29)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
221}
222
223// === User type for allOf example ===
224
225#[allow(dead_code)]
226struct User {
227    email: String,
228    name: String,
229}
230
231impl ToSchema for User {
232    fn schema_name() -> &'static str {
233        "User"
234    }
235
236    fn schema() -> Schema {
237        Schema::object()
238            .property("email", Schema::string().format("email"))
239            .property("name", Schema::string().min_length(1))
240            .required(&["email", "name"])
241    }
More examples
Hide additional examples
examples/user_api.rs (line 45)
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    }
Source

pub fn max_length(self, max: usize) -> Self

Set maximum length for strings.

Examples found in repository?
examples/v08_features.rs (line 29)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
More examples
Hide additional examples
examples/user_api.rs (line 46)
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    }
Source

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

Set regex pattern for strings.

Examples found in repository?
examples/user_api.rs (line 86)
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    }
Source

pub fn minimum(self, min: impl Into<f64>) -> Self

Set minimum value for numbers.

Examples found in repository?
examples/v08_features.rs (line 34)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
104}
105
106// === 3. Request/Response Modifiers: readOnly, writeOnly, deprecated ===
107
108#[allow(dead_code)]
109struct UserAccount {
110    id: String,
111    email: String,
112    password: String,
113    created_at: String,
114    old_username: Option<String>,
115}
116
117impl ToSchema for UserAccount {
118    fn schema_name() -> &'static str {
119        "UserAccount"
120    }
121
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
158}
159
160// === 4. Vendor Extensions for Non-Mappable Validations ===
161
162#[allow(dead_code)]
163struct DateRange {
164    start_date: String,
165    end_date: String,
166}
167
168impl ToSchema for DateRange {
169    fn schema_name() -> &'static str {
170        "DateRange"
171    }
172
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
More examples
Hide additional examples
examples/user_api.rs (line 38)
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    }
Source

pub fn maximum(self, max: impl Into<f64>) -> Self

Set maximum value for numbers.

Examples found in repository?
examples/user_api.rs (line 39)
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    }
Source

pub fn multiple_of(self, divisor: impl Into<f64>) -> Self

Set multiple_of constraint for numbers.

Source

pub fn min_items(self, min: usize) -> Self

Set minimum items for arrays.

Examples found in repository?
examples/user_api.rs (line 124)
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    }
Source

pub fn max_items(self, max: usize) -> Self

Set maximum items for arrays.

Examples found in repository?
examples/user_api.rs (line 125)
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    }
Source

pub fn unique_items(self, unique: bool) -> Self

Set unique items constraint for arrays.

Source

pub fn enum_values<T: Serialize>(self, values: &[T]) -> Self

Set enum values.

§Panics

Panics if any value cannot be serialized to JSON. Use Self::try_enum_values for a non-panicking alternative.

Examples found in repository?
examples/v08_features.rs (line 28)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
38}
39
40/// Admin user: inherits from User AND adds admin field (composition with allOf)
41#[allow(dead_code)]
42struct AdminUser {
43    // Inherits all User fields + additional fields
44    admin: bool,
45}
46
47impl ToSchema for AdminUser {
48    fn schema_name() -> &'static str {
49        "AdminUser"
50    }
51
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
More examples
Hide additional examples
examples/user_api.rs (line 52)
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    }
Source

pub fn try_enum_values<T: Serialize>(self, values: &[T]) -> Result<Self, Error>

Set enum values (non-panicking version).

Returns an error if any value cannot be serialized to JSON.

Source

pub fn any_of(schemas: Vec<Schema>) -> Self

Create a schema that matches any of the given schemas (union type).

§Example
use domainstack_schema::Schema;

let schema = Schema::any_of(vec![
    Schema::string(),
    Schema::integer(),
]);
Examples found in repository?
examples/v08_features.rs (lines 26-36)
25    fn schema() -> Schema {
26        Schema::any_of(vec![
27            Schema::object()
28                .property("type", Schema::string().enum_values(&["card"]))
29                .property("cardNumber", Schema::string().min_length(16).max_length(16))
30                .property("cvv", Schema::string().min_length(3).max_length(4))
31                .required(&["type", "cardNumber", "cvv"]),
32            Schema::object()
33                .property("type", Schema::string().enum_values(&["cash"]))
34                .property("amount", Schema::number().minimum(0))
35                .required(&["type", "amount"]),
36        ])
37    }
Source

pub fn all_of(schemas: Vec<Schema>) -> Self

Create a schema that matches all of the given schemas (intersection/composition).

§Example
use domainstack_schema::Schema;

let schema = Schema::all_of(vec![
    Schema::reference("BaseUser"),
    Schema::object().property("admin", Schema::boolean()),
]);
Examples found in repository?
examples/v08_features.rs (lines 53-59)
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
Source

pub fn one_of(schemas: Vec<Schema>) -> Self

Create a schema that matches exactly one of the given schemas (discriminated union).

§Example
use domainstack_schema::Schema;

let schema = Schema::one_of(vec![
    Schema::object().property("type", Schema::string().enum_values(&["card"])),
    Schema::object().property("type", Schema::string().enum_values(&["cash"])),
]);
Source

pub fn default<T: Serialize>(self, value: T) -> Self

Set a default value for this schema.

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

let schema = Schema::string().default(json!("guest"));
§Panics

Panics if the value cannot be serialized to JSON. Use Self::try_default for a non-panicking alternative.

Examples found in repository?
examples/v08_features.rs (line 56)
52    fn schema() -> Schema {
53        Schema::all_of(vec![
54            Schema::reference("User"),
55            Schema::object()
56                .property("admin", Schema::boolean().default(json!(false)))
57                .property("permissions", Schema::array(Schema::string()))
58                .required(&["admin"]),
59        ])
60        .description("Admin user with elevated permissions")
61    }
62}
63
64// === 2. Metadata: default, example, examples ===
65
66#[allow(dead_code)]
67struct UserSettings {
68    theme: String,
69    language: String,
70    notifications_enabled: bool,
71}
72
73impl ToSchema for UserSettings {
74    fn schema_name() -> &'static str {
75        "UserSettings"
76    }
77
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
Source

pub fn try_default<T: Serialize>(self, value: T) -> Result<Self, Error>

Set a default value for this schema (non-panicking version).

Returns an error if the value cannot be serialized to JSON.

Source

pub fn example<T: Serialize>(self, value: T) -> Self

Set an example value for this schema.

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

let schema = Schema::string().example(json!("john_doe"));
§Panics

Panics if the value cannot be serialized to JSON. Use Self::try_example for a non-panicking alternative.

Examples found in repository?
examples/v08_features.rs (line 86)
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
Source

pub fn try_example<T: Serialize>(self, value: T) -> Result<Self, Error>

Set an example value for this schema (non-panicking version).

Returns an error if the value cannot be serialized to JSON.

Source

pub fn examples<T: Serialize>(self, values: Vec<T>) -> Self

Set multiple example values for this schema.

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

let schema = Schema::string().examples(vec![
    json!("alice"),
    json!("bob"),
]);
§Panics

Panics if any value cannot be serialized to JSON. Use Self::try_examples for a non-panicking alternative.

Examples found in repository?
examples/v08_features.rs (line 93)
78    fn schema() -> Schema {
79        Schema::object()
80            .description("User preferences and settings")
81            .property(
82                "theme",
83                Schema::string()
84                    .enum_values(&["light", "dark", "auto"])
85                    .default(json!("auto"))
86                    .example(json!("dark"))
87                    .description("UI theme preference"),
88            )
89            .property(
90                "language",
91                Schema::string()
92                    .default(json!("en"))
93                    .examples(vec![json!("en"), json!("es"), json!("fr")])
94                    .description("Preferred language code (ISO 639-1)"),
95            )
96            .property(
97                "notificationsEnabled",
98                Schema::boolean()
99                    .default(json!(true))
100                    .description("Enable/disable notifications"),
101            )
102            .required(&["theme", "language"])
103    }
Source

pub fn try_examples<T: Serialize>(self, values: Vec<T>) -> Result<Self, Error>

Set multiple example values for this schema (non-panicking version).

Returns an error if any value cannot be serialized to JSON.

Source

pub fn read_only(self, read_only: bool) -> Self

Mark this field as read-only (returned in responses, not accepted in requests).

§Example
use domainstack_schema::Schema;

let schema = Schema::string().read_only(true);
Examples found in repository?
examples/v08_features.rs (line 128)
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
Source

pub fn write_only(self, write_only: bool) -> Self

Mark this field as write-only (accepted in requests, not returned in responses).

§Example
use domainstack_schema::Schema;

let password = Schema::string()
    .format("password")
    .write_only(true);
Examples found in repository?
examples/v08_features.rs (line 140)
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
Source

pub fn deprecated(self, deprecated: bool) -> Self

Mark this field as deprecated.

§Example
use domainstack_schema::Schema;

let schema = Schema::string()
    .deprecated(true)
    .description("Use 'new_field' instead");
Examples found in repository?
examples/v08_features.rs (line 153)
122    fn schema() -> Schema {
123        Schema::object()
124            .description("User account with request/response field modifiers")
125            .property(
126                "id",
127                Schema::string()
128                    .read_only(true)
129                    .description("Auto-generated user ID (returned in responses only)"),
130            )
131            .property(
132                "email",
133                Schema::string().format("email").description("User email"),
134            )
135            .property(
136                "password",
137                Schema::string()
138                    .format("password")
139                    .min_length(8)
140                    .write_only(true)
141                    .description("Password (accepted in requests only, never returned)"),
142            )
143            .property(
144                "createdAt",
145                Schema::string()
146                    .format("date-time")
147                    .read_only(true)
148                    .description("Account creation timestamp"),
149            )
150            .property(
151                "oldUsername",
152                Schema::string()
153                    .deprecated(true)
154                    .description("Deprecated: Use 'email' instead"),
155            )
156            .required(&["email", "password"])
157    }
Source

pub fn extension<T: Serialize>(self, key: impl Into<String>, value: T) -> Self

Add a vendor extension (for validations that don’t map to OpenAPI).

Extension keys should start with “x-”.

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

let schema = Schema::object()
    .property("end_date", Schema::string().format("date"))
    .extension("x-domainstack-validations", json!({
        "cross_field": ["end_date > start_date"]
    }));
§Panics

Panics if the value cannot be serialized to JSON. Use Self::try_extension for a non-panicking alternative.

Examples found in repository?
examples/v08_features.rs (lines 180-186)
173    fn schema() -> Schema {
174        Schema::object()
175            .description("Date range with cross-field validation")
176            .property("startDate", Schema::string().format("date"))
177            .property("endDate", Schema::string().format("date"))
178            .required(&["startDate", "endDate"])
179            // Cross-field validation doesn't map to OpenAPI, so use vendor extension
180            .extension(
181                "x-domainstack-validations",
182                json!({
183                    "cross_field": ["endDate > startDate"],
184                    "description": "End date must be after start date"
185                }),
186            )
187    }
188}
189
190#[allow(dead_code)]
191struct OrderForm {
192    total: f64,
193    minimum_order: f64,
194    requires_minimum: bool,
195}
196
197impl ToSchema for OrderForm {
198    fn schema_name() -> &'static str {
199        "OrderForm"
200    }
201
202    fn schema() -> Schema {
203        Schema::object()
204            .description("Order form with conditional validation")
205            .property("total", Schema::number().minimum(0))
206            .property("minimumOrder", Schema::number().minimum(0))
207            .property("requiresMinimum", Schema::boolean())
208            .required(&["total", "minimumOrder", "requiresMinimum"])
209            // Conditional validation doesn't map to OpenAPI
210            .extension(
211                "x-domainstack-validations",
212                json!({
213                    "conditional": {
214                        "when": "requiresMinimum == true",
215                        "then": "total >= minimumOrder"
216                    },
217                    "description": "When minimum is required, total must meet it"
218                }),
219            )
220    }
Source

pub fn try_extension<T: Serialize>( self, key: impl Into<String>, value: T, ) -> Result<Self, Error>

Add a vendor extension (non-panicking version).

Extension keys should start with “x-”. Returns an error if the value cannot be serialized to JSON.

Trait Implementations§

Source§

impl Clone for Schema

Source§

fn clone(&self) -> Schema

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Schema

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Schema

Source§

fn default() -> Self

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

impl<'de> Deserialize<'de> for Schema

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for Schema

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,