animi_okapi/
openapi3.rs

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    /// URL to the terms of service.
74    #[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    // TODO this should probably be an enum, not String
260    #[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// maybe this should just been inlined into Parameter as fields?
277#[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)] // Removing this requires breaking changes to API.
281pub 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    // This also sets `type`
373    #[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    // TODO operationRef XOR operationId must be specified
450    #[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}