reinhardt_conf/settings/
openapi.rs1use reinhardt_macros::settings;
19
20#[settings(fragment = true, section = "openapi")]
42#[non_exhaustive]
43pub struct OpenApiSettings {
44 #[serde(default = "default_true")]
49 pub enabled: bool,
50
51 #[serde(default = "default_json_path")]
55 pub json_path: String,
56
57 #[serde(default = "default_swagger_path")]
61 pub swagger_path: String,
62
63 #[serde(default = "default_redoc_path")]
67 pub redoc_path: String,
68
69 #[serde(default = "default_title")]
73 pub title: String,
74
75 #[serde(default = "default_version")]
79 pub version: String,
80
81 #[serde(default)]
85 pub description: Option<String>,
86}
87
88impl Default for OpenApiSettings {
89 fn default() -> Self {
90 Self {
91 enabled: true,
92 json_path: "/api/openapi.json".to_string(),
93 swagger_path: "/api/docs".to_string(),
94 redoc_path: "/api/redoc".to_string(),
95 title: "API Documentation".to_string(),
96 version: "1.0.0".to_string(),
97 description: None,
98 }
99 }
100}
101
102fn default_true() -> bool {
104 true
105}
106
107fn default_json_path() -> String {
108 "/api/openapi.json".to_string()
109}
110
111fn default_swagger_path() -> String {
112 "/api/docs".to_string()
113}
114
115fn default_redoc_path() -> String {
116 "/api/redoc".to_string()
117}
118
119fn default_title() -> String {
120 "API Documentation".to_string()
121}
122
123fn default_version() -> String {
124 "1.0.0".to_string()
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::settings::fragment::SettingsFragment;
131 use rstest::rstest;
132
133 #[rstest]
134 fn test_openapi_section_name() {
135 let section = OpenApiSettings::section();
137
138 assert_eq!(section, "openapi");
140 }
141
142 #[rstest]
143 fn test_openapi_default_values() {
144 let settings = OpenApiSettings::default();
146
147 assert!(settings.enabled);
149 assert_eq!(settings.json_path, "/api/openapi.json");
150 assert_eq!(settings.swagger_path, "/api/docs");
151 assert_eq!(settings.redoc_path, "/api/redoc");
152 assert_eq!(settings.title, "API Documentation");
153 assert_eq!(settings.version, "1.0.0");
154 assert_eq!(settings.description, None);
155 }
156
157 #[rstest]
158 fn test_openapi_serde_roundtrip() {
159 let original = OpenApiSettings {
161 title: "My API".to_string(),
162 version: "2.0.0".to_string(),
163 description: Some("Custom API".to_string()),
164 ..Default::default()
165 };
166
167 let json = serde_json::to_string(&original).unwrap();
169 let deserialized: OpenApiSettings = serde_json::from_str(&json).unwrap();
170
171 assert_eq!(deserialized.title, "My API");
173 assert_eq!(deserialized.version, "2.0.0");
174 assert_eq!(deserialized.description, Some("Custom API".to_string()));
175 assert!(deserialized.enabled);
176 }
177
178 #[rstest]
179 fn test_openapi_serde_missing_fields_use_defaults() {
180 let json = r#"{"title":"Test API"}"#;
182
183 let settings: OpenApiSettings = serde_json::from_str(json).unwrap();
185
186 assert_eq!(settings.title, "Test API");
188 assert_eq!(settings.version, "1.0.0");
189 assert!(settings.enabled);
190 assert_eq!(settings.json_path, "/api/openapi.json");
191 assert_eq!(settings.swagger_path, "/api/docs");
192 assert_eq!(settings.redoc_path, "/api/redoc");
193 assert_eq!(settings.description, None);
194 }
195
196 #[rstest]
197 fn test_openapi_toml_deserialization() {
198 let toml_str = r#"
200enabled = true
201title = "My REST API"
202version = "3.0.0"
203swagger_path = "/docs/swagger"
204redoc_path = "/docs/redoc"
205json_path = "/docs/openapi.json"
206description = "Full API documentation"
207"#;
208
209 let settings: OpenApiSettings = toml::from_str(toml_str).expect("failed to parse TOML");
211
212 assert!(settings.enabled);
214 assert_eq!(settings.title, "My REST API");
215 assert_eq!(settings.version, "3.0.0");
216 assert_eq!(settings.swagger_path, "/docs/swagger");
217 assert_eq!(settings.redoc_path, "/docs/redoc");
218 assert_eq!(settings.json_path, "/docs/openapi.json");
219 assert_eq!(
220 settings.description,
221 Some("Full API documentation".to_string())
222 );
223 }
224
225 #[rstest]
226 fn test_openapi_toml_partial_uses_defaults() {
227 let toml_str = r#"
229title = "Partial API"
230"#;
231
232 let settings: OpenApiSettings = toml::from_str(toml_str).expect("failed to parse TOML");
234
235 assert!(settings.enabled);
237 assert_eq!(settings.title, "Partial API");
238 assert_eq!(settings.version, "1.0.0");
239 assert_eq!(settings.swagger_path, "/api/docs");
240 }
241
242 #[rstest]
243 fn test_openapi_disabled() {
244 let json = r#"{"enabled":false}"#;
246
247 let settings: OpenApiSettings = serde_json::from_str(json).unwrap();
249
250 assert!(!settings.enabled);
252 assert_eq!(settings.title, "API Documentation");
253 }
254
255 #[rstest]
256 fn test_has_openapi_settings_trait() {
257 struct Wrapper {
259 openapi: OpenApiSettings,
260 }
261
262 impl HasOpenApiSettings for Wrapper {
263 fn openapi(&self) -> &OpenApiSettings {
264 &self.openapi
265 }
266 }
267
268 let wrapper = Wrapper {
269 openapi: OpenApiSettings {
270 title: "Trait Test".to_string(),
271 ..Default::default()
272 },
273 };
274
275 let settings = wrapper.openapi();
277
278 assert_eq!(settings.title, "Trait Test");
280 }
281}