1use crate::Map;
2pub use schemars::schema::SchemaObject;
3#[cfg(feature = "impl_json_schema")]
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8pub type Object = Map<String, Value>;
9pub type SecurityRequirement = Map<String, Vec<String>>;
10
11#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
12#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
13#[serde(untagged)]
14pub enum RefOr<T> {
15 Ref(Ref),
16 Object(T),
17}
18
19#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
20#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
21pub struct Ref {
22 #[serde(rename = "$ref")]
23 pub reference: String,
24}
25
26impl<T> From<T> for RefOr<T> {
27 fn from(o: T) -> Self {
28 RefOr::<T>::Object(o)
29 }
30}
31
32impl OpenApi {
33 pub fn new() -> Self {
34 OpenApi {
35 openapi: Self::default_version(),
36 ..Default::default()
37 }
38 }
39
40 pub fn default_version() -> String {
41 "3.0.0".to_owned()
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
46#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
47#[serde(rename_all = "camelCase")]
48pub struct OpenApi {
49 pub openapi: String,
50 pub info: Info,
51 #[serde(default, skip_serializing_if = "Vec::is_empty")]
52 pub servers: Vec<Server>,
53 pub paths: Map<String, PathItem>,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
55 pub components: Option<Components>,
56 #[serde(default, skip_serializing_if = "Vec::is_empty")]
57 pub security: Vec<SecurityRequirement>,
58 #[serde(default, skip_serializing_if = "Vec::is_empty")]
59 pub tags: Vec<Tag>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub external_docs: Option<ExternalDocs>,
62 #[serde(flatten)]
63 pub extensions: Object,
64}
65
66#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
67#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
68#[serde(rename_all = "camelCase")]
69pub struct Info {
70 pub title: String,
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 pub description: Option<String>,
73 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub terms_of_service: Option<String>,
76 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub contact: Option<Contact>,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
79 pub license: Option<License>,
80 pub version: String,
81 #[serde(flatten)]
82 pub extensions: Object,
83}
84
85#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
86#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
87#[serde(default, rename_all = "camelCase")]
88pub struct Contact {
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub name: Option<String>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub url: Option<String>,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub email: Option<String>,
95 #[serde(flatten)]
96 pub extensions: Object,
97}
98
99#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
100#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
101#[serde(rename_all = "camelCase")]
102pub struct License {
103 pub name: String,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub url: Option<String>,
106 #[serde(flatten)]
107 pub extensions: Object,
108}
109
110#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
111#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
112#[serde(rename_all = "camelCase")]
113pub struct Server {
114 pub url: String,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
116 pub description: Option<String>,
117 #[serde(default, skip_serializing_if = "Map::is_empty")]
118 pub variables: Map<String, ServerVariable>,
119 #[serde(flatten)]
120 pub extensions: Object,
121}
122
123#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
124#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
125#[serde(rename_all = "camelCase")]
126pub struct ServerVariable {
127 #[serde(default, rename = "enum", skip_serializing_if = "Option::is_none")]
128 pub enumeration: Option<Vec<String>>,
129 pub default: String,
130 #[serde(default, skip_serializing_if = "Option::is_none")]
131 pub description: Option<String>,
132 #[serde(flatten)]
133 pub extensions: Object,
134}
135
136#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
137#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
138#[serde(default, rename_all = "camelCase")]
139pub struct PathItem {
140 #[serde(default, rename = "$ref", skip_serializing_if = "Option::is_none")]
141 pub reference: Option<String>,
142 #[serde(default, skip_serializing_if = "Option::is_none")]
143 pub summary: Option<String>,
144 #[serde(default, skip_serializing_if = "Option::is_none")]
145 pub description: Option<String>,
146 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub get: Option<Operation>,
148 #[serde(default, skip_serializing_if = "Option::is_none")]
149 pub put: Option<Operation>,
150 #[serde(default, skip_serializing_if = "Option::is_none")]
151 pub post: Option<Operation>,
152 #[serde(default, skip_serializing_if = "Option::is_none")]
153 pub delete: Option<Operation>,
154 #[serde(default, skip_serializing_if = "Option::is_none")]
155 pub options: Option<Operation>,
156 #[serde(default, skip_serializing_if = "Option::is_none")]
157 pub head: Option<Operation>,
158 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub patch: Option<Operation>,
160 #[serde(default, skip_serializing_if = "Option::is_none")]
161 pub trace: Option<Operation>,
162 #[serde(default, skip_serializing_if = "Option::is_none")]
163 pub servers: Option<Vec<Server>>,
164 #[serde(default, skip_serializing_if = "Vec::is_empty")]
165 pub parameters: Vec<RefOr<Parameter>>,
166 #[serde(flatten)]
167 pub extensions: Object,
168}
169
170#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
171#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
172#[serde(rename_all = "camelCase")]
173pub struct Operation {
174 #[serde(default, skip_serializing_if = "Vec::is_empty")]
175 pub tags: Vec<String>,
176 #[serde(default, skip_serializing_if = "Option::is_none")]
177 pub summary: Option<String>,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
179 pub description: Option<String>,
180 #[serde(default, skip_serializing_if = "Option::is_none")]
181 pub external_docs: Option<ExternalDocs>,
182 #[serde(default, skip_serializing_if = "Option::is_none")]
183 pub operation_id: Option<String>,
184 #[serde(default, skip_serializing_if = "Vec::is_empty")]
185 pub parameters: Vec<RefOr<Parameter>>,
186 #[serde(default, skip_serializing_if = "Option::is_none")]
187 pub request_body: Option<RefOr<RequestBody>>,
188 pub responses: Responses,
189 #[serde(default, skip_serializing_if = "Map::is_empty")]
190 pub callbacks: Map<String, RefOr<Callback>>,
191 #[serde(default, skip_serializing_if = "is_false")]
192 pub deprecated: bool,
193 #[serde(default, skip_serializing_if = "Option::is_none")]
194 pub security: Option<Vec<SecurityRequirement>>,
195 #[serde(default, skip_serializing_if = "Option::is_none")]
196 pub servers: Option<Vec<Server>>,
197 #[serde(flatten)]
198 pub extensions: Object,
199}
200
201#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
202#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
203#[serde(default, rename_all = "camelCase")]
204pub struct Responses {
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub default: Option<RefOr<Response>>,
207 #[serde(flatten)]
208 pub responses: Map<String, RefOr<Response>>,
209 #[serde(flatten)]
210 pub extensions: Object,
211}
212
213#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
214#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
215#[serde(default, rename_all = "camelCase")]
216pub struct Components {
217 #[serde(default, skip_serializing_if = "Map::is_empty")]
218 pub schemas: Map<String, SchemaObject>,
219 #[serde(default, skip_serializing_if = "Map::is_empty")]
220 pub responses: Map<String, RefOr<Response>>,
221 #[serde(default, skip_serializing_if = "Map::is_empty")]
222 pub parameters: Map<String, RefOr<Parameter>>,
223 #[serde(default, skip_serializing_if = "Map::is_empty")]
224 pub examples: Map<String, RefOr<Example>>,
225 #[serde(default, skip_serializing_if = "Map::is_empty")]
226 pub request_bodies: Map<String, RefOr<RequestBody>>,
227 #[serde(default, skip_serializing_if = "Map::is_empty")]
228 pub headers: Map<String, RefOr<Header>>,
229 #[serde(default, skip_serializing_if = "Map::is_empty")]
230 pub security_schemes: Map<String, RefOr<SecurityScheme>>,
231 #[serde(default, skip_serializing_if = "Map::is_empty")]
232 pub links: Map<String, RefOr<Link>>,
233 #[serde(default, skip_serializing_if = "Map::is_empty")]
234 pub callbacks: Map<String, RefOr<Callback>>,
235 #[serde(flatten)]
236 pub extensions: Object,
237}
238
239#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
240#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
241#[serde(rename_all = "camelCase")]
242pub struct Response {
243 pub description: String,
244 #[serde(default, skip_serializing_if = "Map::is_empty")]
245 pub headers: Map<String, RefOr<Header>>,
246 #[serde(default, skip_serializing_if = "Map::is_empty")]
247 pub content: Map<String, MediaType>,
248 #[serde(default, skip_serializing_if = "Map::is_empty")]
249 pub links: Map<String, RefOr<Link>>,
250 #[serde(flatten)]
251 pub extensions: Object,
252}
253
254#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
255#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
256#[serde(rename_all = "camelCase")]
257pub struct Parameter {
258 pub name: String,
259 #[serde(rename = "in")]
261 pub location: String,
262 #[serde(default, skip_serializing_if = "Option::is_none")]
263 pub description: Option<String>,
264 #[serde(default, skip_serializing_if = "is_false")]
265 pub required: bool,
266 #[serde(default, skip_serializing_if = "is_false")]
267 pub deprecated: bool,
268 #[serde(default, skip_serializing_if = "is_false")]
269 pub allow_empty_value: bool,
270 #[serde(flatten)]
271 pub value: ParameterValue,
272 #[serde(flatten)]
273 pub extensions: Object,
274}
275
276#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
278#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
279#[serde(untagged, rename_all = "camelCase")]
280#[allow(clippy::large_enum_variant)] pub enum ParameterValue {
282 Schema {
283 #[serde(default, skip_serializing_if = "Option::is_none")]
284 style: Option<ParameterStyle>,
285 #[serde(default, skip_serializing_if = "Option::is_none")]
286 explode: Option<bool>,
287 #[serde(default, skip_serializing_if = "is_false")]
288 allow_reserved: bool,
289 schema: SchemaObject,
290 #[serde(default, skip_serializing_if = "Option::is_none")]
291 example: Option<Value>,
292 #[serde(default, skip_serializing_if = "Option::is_none")]
293 examples: Option<Map<String, Example>>,
294 },
295 Content {
296 content: Map<String, MediaType>,
297 },
298}
299
300#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
301#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
302#[serde(rename_all = "camelCase")]
303pub enum ParameterStyle {
304 Matrix,
305 Label,
306 Form,
307 Simple,
308 SpaceDelimited,
309 PipeDelimited,
310 DeepObject,
311}
312
313#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
314#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
315#[serde(rename_all = "camelCase")]
316pub struct Example {
317 #[serde(default, skip_serializing_if = "Option::is_none")]
318 pub summary: Option<String>,
319 #[serde(default, skip_serializing_if = "Option::is_none")]
320 pub description: Option<String>,
321 #[serde(flatten)]
322 pub value: ExampleValue,
323 #[serde(flatten)]
324 pub extensions: Object,
325}
326
327#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
328#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
329#[serde(rename_all = "camelCase")]
330pub enum ExampleValue {
331 Value(Value),
332 ExternalValue(String),
333}
334
335#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
336#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
337#[serde(rename_all = "camelCase")]
338pub struct RequestBody {
339 #[serde(default, skip_serializing_if = "Option::is_none")]
340 pub description: Option<String>,
341 pub content: Map<String, MediaType>,
342 #[serde(default, skip_serializing_if = "is_false")]
343 pub required: bool,
344 #[serde(flatten)]
345 pub extensions: Object,
346}
347
348#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
349#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
350#[serde(rename_all = "camelCase")]
351pub struct Header {
352 #[serde(default, skip_serializing_if = "Option::is_none")]
353 pub description: Option<String>,
354 #[serde(default, skip_serializing_if = "is_false")]
355 pub required: bool,
356 #[serde(default, skip_serializing_if = "is_false")]
357 pub deprecated: bool,
358 #[serde(default, skip_serializing_if = "is_false")]
359 pub allow_empty_value: bool,
360 #[serde(flatten)]
361 pub value: ParameterValue,
362 #[serde(flatten)]
363 pub extensions: Object,
364}
365
366#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
367#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
368#[serde(rename_all = "camelCase")]
369pub struct SecurityScheme {
370 #[serde(default, skip_serializing_if = "Option::is_none")]
371 pub description: Option<String>,
372 #[serde(flatten)]
374 pub data: SecuritySchemeData,
375 #[serde(flatten)]
376 pub extensions: Object,
377}
378
379#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
380#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
381#[serde(tag = "type", rename_all = "camelCase")]
382#[allow(clippy::large_enum_variant)]
383pub enum SecuritySchemeData {
384 #[serde(rename_all = "camelCase")]
385 ApiKey {
386 name: String,
387 #[serde(rename = "in")]
388 location: String,
389 },
390 #[serde(rename_all = "camelCase")]
391 Http {
392 scheme: String,
393 #[serde(default, skip_serializing_if = "Option::is_none")]
394 bearer_format: Option<String>,
395 },
396 #[serde(rename = "oauth2", rename_all = "camelCase")]
397 OAuth2 { flows: OAuthFlows },
398 #[serde(rename_all = "camelCase")]
399 OpenIdConnect { open_id_connect_url: String },
400}
401
402#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
403#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
404#[serde(rename_all = "camelCase")]
405pub enum OAuthFlows {
406 #[serde(rename_all = "camelCase")]
407 Implicit {
408 authorization_url: String,
409 #[serde(default, skip_serializing_if = "Option::is_none")]
410 refresh_url: Option<String>,
411 scopes: Map<String, String>,
412 #[serde(flatten)]
413 extensions: Object,
414 },
415 #[serde(rename_all = "camelCase")]
416 Password {
417 token_url: String,
418 #[serde(default, skip_serializing_if = "Option::is_none")]
419 refresh_url: Option<String>,
420 scopes: Map<String, String>,
421 #[serde(flatten)]
422 extensions: Object,
423 },
424 #[serde(rename_all = "camelCase")]
425 ClientCredentials {
426 token_url: String,
427 #[serde(default, skip_serializing_if = "Option::is_none")]
428 refresh_url: Option<String>,
429 scopes: Map<String, String>,
430 #[serde(flatten)]
431 extensions: Object,
432 },
433 #[serde(rename_all = "camelCase")]
434 AuthorizationCode {
435 authorization_url: String,
436 token_url: String,
437 #[serde(default, skip_serializing_if = "Option::is_none")]
438 refresh_url: Option<String>,
439 scopes: Map<String, String>,
440 #[serde(flatten)]
441 extensions: Object,
442 },
443}
444
445#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
446#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
447#[serde(rename_all = "camelCase")]
448pub struct Link {
449 #[serde(default, skip_serializing_if = "Option::is_none")]
451 pub operation_ref: Option<String>,
452 #[serde(default, skip_serializing_if = "Option::is_none")]
453 pub operation_id: Option<String>,
454 #[serde(default, skip_serializing_if = "Map::is_empty")]
455 pub parameters: Map<String, Value>,
456 #[serde(default, skip_serializing_if = "Option::is_none")]
457 pub request_body: Option<Value>,
458 #[serde(default, skip_serializing_if = "Option::is_none")]
459 pub description: Option<String>,
460 #[serde(default, skip_serializing_if = "Option::is_none")]
461 pub server: Option<Server>,
462 #[serde(flatten)]
463 pub extensions: Object,
464}
465
466#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
467#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
468#[serde(rename_all = "camelCase")]
469pub struct Callback {
470 #[serde(flatten)]
471 pub callbacks: Map<String, PathItem>,
472 #[serde(flatten)]
473 pub extensions: Object,
474}
475
476#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
477#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
478#[serde(default, rename_all = "camelCase")]
479pub struct MediaType {
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub schema: Option<SchemaObject>,
482 #[serde(skip_serializing_if = "Option::is_none")]
483 pub example: Option<Value>,
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub examples: Option<Map<String, Example>>,
486 #[serde(skip_serializing_if = "Map::is_empty")]
487 pub encoding: Map<String, Encoding>,
488 #[serde(flatten)]
489 pub extensions: Object,
490}
491
492#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
493#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
494#[serde(rename_all = "camelCase")]
495pub struct Tag {
496 pub name: String,
497 #[serde(default, skip_serializing_if = "Option::is_none")]
498 pub description: Option<String>,
499 #[serde(default, skip_serializing_if = "Option::is_none")]
500 pub external_docs: Option<ExternalDocs>,
501 #[serde(flatten)]
502 pub extensions: Object,
503}
504
505#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
506#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
507#[serde(rename_all = "camelCase")]
508pub struct ExternalDocs {
509 #[serde(default, skip_serializing_if = "Option::is_none")]
510 pub description: Option<String>,
511 pub url: String,
512 #[serde(flatten)]
513 pub extensions: Object,
514}
515
516#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
517#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
518#[serde(default, rename_all = "camelCase")]
519pub struct Encoding {
520 #[serde(skip_serializing_if = "Option::is_none")]
521 pub content_type: Option<String>,
522 #[serde(skip_serializing_if = "Map::is_empty")]
523 pub headers: Map<String, RefOr<Header>>,
524 #[serde(skip_serializing_if = "Option::is_none")]
525 pub style: Option<String>,
526 #[serde(skip_serializing_if = "Option::is_none")]
527 pub explode: Option<bool>,
528 #[serde(skip_serializing_if = "is_false")]
529 pub allow_reserved: bool,
530 #[serde(flatten)]
531 pub extensions: Object,
532}
533
534fn is_false(b: impl std::borrow::Borrow<bool>) -> bool {
535 !b.borrow()
536}