Skip to main content

utoipa/openapi/
xml.rs

1//! Implements [OpenAPI Xml Object][xml_object] types.
2//!
3//! [xml_object]: https://spec.openapis.org/oas/latest.html#xml-object
4use std::borrow::Cow;
5
6use serde::{Deserialize, Serialize};
7
8use super::{builder, set_value};
9
10builder! {
11    /// # Examples
12    ///
13    /// Create [`Xml`] with [`XmlBuilder`].
14    /// ```rust
15    /// # use utoipa::openapi::xml::XmlBuilder;
16    ///  let xml = XmlBuilder::new()
17    ///     .name(Some("some_name"))
18    ///     .prefix(Some("prefix"))
19    ///     .build();
20    /// ```
21    XmlBuilder;
22    /// Implements [OpenAPI Xml Object][xml_object].
23    ///
24    /// Can be used to modify xml output format of specific [OpenAPI Schema Object][schema_object] which are
25    /// implemented in [`schema`][schema] module.
26    ///
27    /// [xml_object]: https://spec.openapis.org/oas/latest.html#xml-object
28    /// [schema_object]: https://spec.openapis.org/oas/latest.html#schema-object
29    /// [schema]: ../schema/index.html
30    #[non_exhaustive]
31    #[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
32    #[cfg_attr(feature = "debug", derive(Debug))]
33    #[serde(rename_all = "camelCase")]
34    pub struct Xml {
35        /// Used to replace the name of attribute or type used in schema property.
36        /// When used with [`Xml::wrapped`] attribute the name will be used as a wrapper name
37        /// for wrapped array instead of the item or type name.
38        #[serde(skip_serializing_if = "Option::is_none")]
39        pub name: Option<Cow<'static, str>>,
40
41        /// Valid uri definition of namespace used in xml.
42        #[serde(skip_serializing_if = "Option::is_none")]
43        pub namespace: Option<Cow<'static, str>>,
44
45        /// Prefix for xml element [`Xml::name`].
46        #[serde(skip_serializing_if = "Option::is_none")]
47        pub prefix: Option<Cow<'static, str>>,
48
49        /// XML node type for this schema.
50        #[serde(skip_serializing_if = "Option::is_none")]
51        pub node_type: Option<Cow<'static, str>>,
52
53        /// Flag deciding will this attribute translate to element attribute instead of xml element.
54        #[serde(skip_serializing_if = "Option::is_none")]
55        pub attribute: Option<bool>,
56
57        /// Flag only usable with array definition. If set to true the output xml will wrap the array of items
58        /// `<pets><pet></pet></pets>` instead of unwrapped `<pet></pet>`.
59        #[serde(skip_serializing_if = "Option::is_none")]
60        pub wrapped: Option<bool>,
61    }
62}
63
64impl Xml {
65    /// Construct a new [`Xml`] object.
66    pub fn new() -> Self {
67        Self {
68            ..Default::default()
69        }
70    }
71}
72
73impl XmlBuilder {
74    /// Add [`Xml::name`] to xml object.
75    ///
76    /// Builder style chainable consuming add name method.
77    pub fn name<S: Into<Cow<'static, str>>>(mut self, name: Option<S>) -> Self {
78        set_value!(self name name.map(|name| name.into()))
79    }
80
81    /// Add [`Xml::namespace`] to xml object.
82    ///
83    /// Builder style chainable consuming add namespace method.
84    pub fn namespace<S: Into<Cow<'static, str>>>(mut self, namespace: Option<S>) -> Self {
85        set_value!(self namespace namespace.map(|namespace| namespace.into()))
86    }
87
88    /// Add [`Xml::prefix`] to xml object.
89    ///
90    /// Builder style chainable consuming add prefix method.
91    pub fn prefix<S: Into<Cow<'static, str>>>(mut self, prefix: Option<S>) -> Self {
92        set_value!(self prefix prefix.map(|prefix| prefix.into()))
93    }
94
95    /// Add [`Xml::node_type`] to xml object.
96    ///
97    /// Builder style chainable consuming add node type method.
98    pub fn node_type<S: Into<Cow<'static, str>>>(mut self, node_type: Option<S>) -> Self {
99        set_value!(self node_type node_type.map(|node_type| node_type.into()))
100    }
101
102    /// Mark [`Xml`] object as attribute. See [`Xml::attribute`].
103    ///
104    /// Builder style chainable consuming add attribute method.
105    pub fn attribute(mut self, attribute: Option<bool>) -> Self {
106        set_value!(self attribute attribute)
107    }
108
109    /// Mark [`Xml`] object wrapped. See [`Xml::wrapped`].
110    ///
111    /// Builder style chainable consuming add wrapped method.
112    pub fn wrapped(mut self, wrapped: Option<bool>) -> Self {
113        set_value!(self wrapped wrapped)
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::Xml;
120
121    #[test]
122    fn xml_new() {
123        let xml = Xml::new();
124
125        assert!(xml.name.is_none());
126        assert!(xml.namespace.is_none());
127        assert!(xml.prefix.is_none());
128        assert!(xml.attribute.is_none());
129        assert!(xml.wrapped.is_none());
130    }
131}