Skip to main content

kynos_openapi/model/paths/
operation.rs

1//! The Operation Object.
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    Map,
7    model::{
8        body::RequestBody, callback::Callback, extensions::Extensions,
9        external_docs::ExternalDocumentation, parameter::Parameter, reference::RefOr,
10        response::Responses, security::requirement::SecurityRequirement, server::Server,
11    },
12};
13
14/// A single API operation on a path.
15#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
16pub struct Operation {
17    /// Tags for grouping this operation.
18    #[serde(default, skip_serializing_if = "Vec::is_empty")]
19    pub tags: Vec<String>,
20
21    /// A short summary of what the operation does.
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub summary: Option<String>,
24
25    /// A verbose explanation. [CommonMark] syntax may be used.
26    ///
27    /// [CommonMark]: https://spec.commonmark.org/
28    #[serde(default, skip_serializing_if = "Option::is_none")]
29    pub description: Option<String>,
30
31    /// Additional external documentation.
32    #[serde(
33        rename = "externalDocs",
34        default,
35        skip_serializing_if = "Option::is_none"
36    )]
37    pub external_docs: Option<ExternalDocumentation>,
38
39    /// A case-sensitive identifier, unique across the whole description.
40    ///
41    /// Optional per the specification, but Kynos always emits one: it is what
42    /// client generators name their methods after, and what a
43    /// [`Link`](crate::Link) refers to.
44    #[serde(
45        rename = "operationId",
46        default,
47        skip_serializing_if = "Option::is_none"
48    )]
49    pub operation_id: Option<String>,
50
51    /// Parameters applying to this operation.
52    ///
53    /// An entry here with the same name and location as one on the enclosing
54    /// [`PathItem`](crate::model::paths::PathItem) overrides it, but cannot
55    /// remove it.
56    #[serde(default, skip_serializing_if = "Vec::is_empty")]
57    pub parameters: Vec<RefOr<Parameter>>,
58
59    /// The request body.
60    #[serde(
61        rename = "requestBody",
62        default,
63        skip_serializing_if = "Option::is_none"
64    )]
65    pub request_body: Option<RefOr<RequestBody>>,
66
67    /// The responses this operation may return.
68    #[serde(default, skip_serializing_if = "Responses::is_empty")]
69    pub responses: Responses,
70
71    /// Out-of-band requests made as part of this operation.
72    #[serde(default, skip_serializing_if = "Map::is_empty")]
73    pub callbacks: Map<RefOr<Callback>>,
74
75    /// Whether this operation is deprecated.
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub deprecated: Option<bool>,
78
79    /// The security requirements, overriding the document-level list.
80    ///
81    /// An empty vector is *not* the same as absent: it removes the
82    /// document-level requirement, making the operation anonymous.
83    #[serde(default, skip_serializing_if = "Option::is_none")]
84    pub security: Option<Vec<SecurityRequirement>>,
85
86    /// Servers serving this operation, overriding wider declarations.
87    #[serde(default, skip_serializing_if = "Vec::is_empty")]
88    pub servers: Vec<Server>,
89
90    /// Specification extensions.
91    #[serde(flatten)]
92    pub extensions: Extensions,
93}
94
95impl Operation {
96    /// Creates an operation identified by `operation_id`.
97    pub fn new(operation_id: impl Into<String>) -> Self {
98        Self {
99            operation_id: Some(operation_id.into()),
100            ..Self::default()
101        }
102    }
103
104    /// Sets the summary.
105    #[must_use]
106    pub fn with_summary(mut self, summary: impl Into<String>) -> Self {
107        self.summary = Some(summary.into());
108        self
109    }
110
111    /// Sets the description.
112    #[must_use]
113    pub fn with_description(mut self, description: impl Into<String>) -> Self {
114        self.description = Some(description.into());
115        self
116    }
117
118    /// Adds a tag.
119    #[must_use]
120    pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
121        self.tags.push(tag.into());
122        self
123    }
124
125    /// Adds a parameter.
126    #[must_use]
127    pub fn with_parameter(mut self, parameter: Parameter) -> Self {
128        self.parameters.push(RefOr::Item(parameter));
129        self
130    }
131
132    /// Sets the request body.
133    #[must_use]
134    pub fn with_request_body(mut self, body: RequestBody) -> Self {
135        self.request_body = Some(RefOr::Item(body));
136        self
137    }
138
139    /// Sets the responses.
140    #[must_use]
141    pub fn with_responses(mut self, responses: Responses) -> Self {
142        self.responses = responses;
143        self
144    }
145
146    /// Adds a security requirement.
147    #[must_use]
148    pub fn with_security(mut self, requirement: SecurityRequirement) -> Self {
149        self.security.get_or_insert_with(Vec::new).push(requirement);
150        self
151    }
152
153    /// Marks the operation deprecated.
154    #[must_use]
155    pub fn deprecated(mut self) -> Self {
156        self.deprecated = Some(true);
157        self
158    }
159}