utoipa/openapi/info.rs
1//! Implements [OpenAPI Metadata][info] types.
2//!
3//! Refer to [`OpenApi`][openapi_trait] trait and [derive documentation][derive]
4//! for examples and usage details.
5//!
6//! [info]: <https://spec.openapis.org/oas/latest.html#info-object>
7//! [openapi_trait]: ../../trait.OpenApi.html
8//! [derive]: ../../derive.OpenApi.html
9
10use serde::{Deserialize, Serialize};
11
12use super::{builder, extensions::Extensions, set_value};
13
14builder! {
15 /// # Examples
16 ///
17 /// Create [`Info`] using [`InfoBuilder`].
18 /// ```rust
19 /// # use utoipa::openapi::{Info, InfoBuilder, ContactBuilder};
20 /// let info = InfoBuilder::new()
21 /// .title("My api")
22 /// .version("1.0.0")
23 /// .contact(Some(ContactBuilder::new()
24 /// .name(Some("Admin Admin"))
25 /// .email(Some("amdin@petapi.com"))
26 /// .build()
27 /// ))
28 /// .build();
29 /// ```
30 InfoBuilder;
31
32 /// OpenAPI [Info][info] object represents metadata of the API.
33 ///
34 /// You can use [`Info::new`] to construct a new [`Info`] object or alternatively use [`InfoBuilder::new`]
35 /// to construct a new [`Info`] with chainable configuration methods.
36 ///
37 /// [info]: <https://spec.openapis.org/oas/latest.html#info-object>
38 #[non_exhaustive]
39 #[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
40 #[cfg_attr(feature = "debug", derive(Debug))]
41 #[serde(rename_all = "camelCase")]
42 pub struct Info {
43 /// Title of the API.
44 pub title: String,
45
46 /// Optional description of the API.
47 ///
48 /// Value supports markdown syntax.
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub description: Option<String>,
51
52 /// Optional url for terms of service.
53 #[serde(skip_serializing_if = "Option::is_none")]
54 pub terms_of_service: Option<String>,
55
56 /// Contact information of exposed API.
57 ///
58 /// See more details at: <https://spec.openapis.org/oas/latest.html#contact-object>.
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub contact: Option<Contact>,
61
62 /// License of the API.
63 ///
64 /// See more details at: <https://spec.openapis.org/oas/latest.html#license-object>.
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub license: Option<License>,
67
68 /// Document version typically the API version.
69 pub version: String,
70
71 /// Optional extensions "x-something".
72 #[serde(skip_serializing_if = "Option::is_none", flatten)]
73 pub extensions: Option<Extensions>,
74 }
75}
76
77impl Info {
78 /// Construct a new [`Info`] object.
79 ///
80 /// This function accepts two arguments. One which is the title of the API and two the
81 /// version of the api document typically the API version.
82 ///
83 /// # Examples
84 ///
85 /// ```rust
86 /// # use utoipa::openapi::Info;
87 /// let info = Info::new("Pet api", "1.1.0");
88 /// ```
89 pub fn new<S: Into<String>>(title: S, version: S) -> Self {
90 Self {
91 title: title.into(),
92 version: version.into(),
93 ..Default::default()
94 }
95 }
96}
97
98impl InfoBuilder {
99 /// Add title of the API.
100 pub fn title<I: Into<String>>(mut self, title: I) -> Self {
101 set_value!(self title title.into())
102 }
103
104 /// Add version of the api document typically the API version.
105 pub fn version<I: Into<String>>(mut self, version: I) -> Self {
106 set_value!(self version version.into())
107 }
108
109 /// Add description of the API.
110 pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
111 set_value!(self description description.map(|description| description.into()))
112 }
113
114 /// Add url for terms of the API.
115 pub fn terms_of_service<S: Into<String>>(mut self, terms_of_service: Option<S>) -> Self {
116 set_value!(self terms_of_service terms_of_service.map(|terms_of_service| terms_of_service.into()))
117 }
118
119 /// Add contact information of the API.
120 pub fn contact(mut self, contact: Option<Contact>) -> Self {
121 set_value!(self contact contact)
122 }
123
124 /// Add license of the API.
125 pub fn license(mut self, license: Option<License>) -> Self {
126 set_value!(self license license)
127 }
128
129 /// Add openapi extensions (x-something) of the API.
130 pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
131 set_value!(self extensions extensions)
132 }
133}
134
135builder! {
136 /// See the [`InfoBuilder`] for combined usage example.
137 ContactBuilder;
138
139 /// OpenAPI [Contact][contact] information of the API.
140 ///
141 /// You can use [`Contact::new`] to construct a new [`Contact`] object or alternatively
142 /// use [`ContactBuilder::new`] to construct a new [`Contact`] with chainable configuration methods.
143 ///
144 /// [contact]: <https://spec.openapis.org/oas/latest.html#contact-object>
145 #[non_exhaustive]
146 #[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
147 #[cfg_attr(feature = "debug", derive(Debug))]
148 #[serde(rename_all = "camelCase")]
149 pub struct Contact {
150 /// Identifying name of the contact person or organization of the API.
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub name: Option<String>,
153
154 /// Url pointing to contact information of the API.
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub url: Option<String>,
157
158 /// Email of the contact person or the organization of the API.
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub email: Option<String>,
161
162 /// Optional extensions "x-something".
163 #[serde(skip_serializing_if = "Option::is_none", flatten)]
164 pub extensions: Option<Extensions>,
165 }
166}
167
168impl Contact {
169 /// Construct a new [`Contact`].
170 pub fn new() -> Self {
171 Default::default()
172 }
173}
174
175impl ContactBuilder {
176 /// Add name contact person or organization of the API.
177 pub fn name<S: Into<String>>(mut self, name: Option<S>) -> Self {
178 set_value!(self name name.map(|name| name.into()))
179 }
180
181 /// Add url pointing to the contact information of the API.
182 pub fn url<S: Into<String>>(mut self, url: Option<S>) -> Self {
183 set_value!(self url url.map(|url| url.into()))
184 }
185
186 /// Add email of the contact person or organization of the API.
187 pub fn email<S: Into<String>>(mut self, email: Option<S>) -> Self {
188 set_value!(self email email.map(|email| email.into()))
189 }
190
191 /// Add openapi extensions (x-something) of the API.
192 pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
193 set_value!(self extensions extensions)
194 }
195}
196
197builder! {
198 LicenseBuilder;
199
200 /// OpenAPI [License][license] information of the API.
201 ///
202 /// [license]: <https://spec.openapis.org/oas/latest.html#license-object>
203 #[non_exhaustive]
204 #[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
205 #[cfg_attr(feature = "debug", derive(Debug))]
206 #[serde(rename_all = "camelCase")]
207 pub struct License {
208 /// Name of the license used e.g MIT or Apache-2.0.
209 pub name: String,
210
211 /// Optional url pointing to the license.
212 #[serde(skip_serializing_if = "Option::is_none")]
213 pub url: Option<String>,
214
215 /// An [SPDX-Licenses][spdx_licence] expression for the API. The _`identifier`_ field
216 /// is mutually exclusive of the _`url`_ field. E.g. Apache-2.0
217 ///
218 /// [spdx_licence]: <https://spdx.org/licenses/>
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub identifier: Option<String>,
221
222 /// Optional extensions "x-something".
223 #[serde(skip_serializing_if = "Option::is_none", flatten)]
224 pub extensions: Option<Extensions>,
225 }
226}
227
228impl License {
229 /// Construct a new [`License`] object.
230 ///
231 /// Function takes name of the license as an argument e.g MIT.
232 pub fn new<S: Into<String>>(name: S) -> Self {
233 Self {
234 name: name.into(),
235 ..Default::default()
236 }
237 }
238}
239
240impl LicenseBuilder {
241 /// Add name of the license used in API.
242 pub fn name<S: Into<String>>(mut self, name: S) -> Self {
243 set_value!(self name name.into())
244 }
245
246 /// Add url pointing to the license used in API.
247 pub fn url<S: Into<String>>(mut self, url: Option<S>) -> Self {
248 set_value!(self url url.map(|url| url.into()))
249 }
250
251 /// Add openapi extensions (x-something) of the API.
252 pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
253 set_value!(self extensions extensions)
254 }
255
256 /// Set identifier of the licence as [SPDX-Licenses][spdx_licence] expression for the API.
257 /// The _`identifier`_ field is mutually exclusive of the _`url`_ field. E.g. Apache-2.0
258 ///
259 /// [spdx_licence]: <https://spdx.org/licenses/>
260 pub fn identifier<S: Into<String>>(mut self, identifier: Option<S>) -> Self {
261 set_value!(self identifier identifier.map(|identifier| identifier.into()))
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::Contact;
268
269 #[test]
270 fn contact_new() {
271 let contact = Contact::new();
272
273 assert!(contact.name.is_none());
274 assert!(contact.url.is_none());
275 assert!(contact.email.is_none());
276 }
277}