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