roas/v3_0/
tag.rs

1//! Tag Object
2
3use crate::common::helpers::{Context, ValidateWithContext, validate_required_string};
4use crate::v3_0::external_documentation::ExternalDocumentation;
5use crate::v3_0::spec::Spec;
6use serde::{Deserialize, Serialize};
7use std::collections::BTreeMap;
8
9/// Adds metadata to a single tag that is used by the Operation Object.
10/// It is not mandatory to have a Tag Object per tag defined in the Operation Object instances.
11///
12/// Specification Example:
13///
14/// ```yaml
15/// name: pet
16/// description: Pets operations
17/// ```
18#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
19#[serde(rename_all = "camelCase")]
20pub struct Tag {
21    /// **Required** The name of the tag.
22    pub name: String,
23
24    /// A short description for the tag.
25    /// [CommonMark](https://spec.commonmark.org) syntax MAY be used for rich text representation.
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub description: Option<String>,
28
29    /// Additional external documentation for this tag.
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub external_docs: Option<ExternalDocumentation>,
32
33    /// Allows extensions to the Swagger Schema.
34    /// The field name MUST begin with `x-`, for example, `x-internal-id`.
35    /// The value can be null, a primitive, an array or an object.
36    #[serde(flatten)]
37    #[serde(with = "crate::common::extensions")]
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub extensions: Option<BTreeMap<String, serde_json::Value>>,
40}
41
42impl ValidateWithContext<Spec> for Tag {
43    fn validate_with_context(&self, ctx: &mut Context<Spec>, path: String) {
44        validate_required_string(&self.name, ctx, format!("{path}.name"));
45        if let Some(doc) = &self.external_docs {
46            doc.validate_with_context(ctx, format!("{path}.externalDocs"));
47        }
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn deserialize() {
57        assert_eq!(
58            serde_json::from_value::<Tag>(serde_json::json!({
59                "name": "pet",
60                "description": "Pets operations",
61                "externalDocs": {
62                    "description": "Find more info here",
63                    "url": "https://example.com/about"
64                },
65            }))
66            .unwrap(),
67            Tag {
68                name: String::from("pet"),
69                description: Some(String::from("Pets operations")),
70                external_docs: Some(ExternalDocumentation {
71                    description: Some(String::from("Find more info here")),
72                    url: String::from("https://example.com/about"),
73                    ..Default::default()
74                }),
75                ..Default::default()
76            },
77            "deserialize name, description and externalDocs"
78        );
79
80        assert_eq!(
81            serde_json::from_value::<Tag>(serde_json::json!({
82                "name": "pet",
83                "description": "Pets operations",
84            }))
85            .unwrap(),
86            Tag {
87                name: String::from("pet"),
88                description: Some(String::from("Pets operations")),
89                ..Default::default()
90            },
91            "deserialize name and description"
92        );
93
94        assert_eq!(
95            serde_json::from_value::<Tag>(serde_json::json!({
96                "name": "pet",
97            }))
98            .unwrap(),
99            Tag {
100                name: String::from("pet"),
101                ..Default::default()
102            },
103            "deserialize name only"
104        );
105    }
106
107    #[test]
108    fn serialize() {
109        assert_eq!(
110            serde_json::to_value(Tag {
111                name: String::from("pet"),
112                description: Some(String::from("Pets operations")),
113                external_docs: Some(ExternalDocumentation {
114                    description: Some(String::from("Find more info here")),
115                    url: String::from("https://example.com/about"),
116                    ..Default::default()
117                }),
118                ..Default::default()
119            })
120            .unwrap(),
121            serde_json::json!({
122                "name": "pet",
123                "description":"Pets operations",
124                "externalDocs": {
125                    "description": "Find more info here",
126                    "url": "https://example.com/about"
127                },
128            }),
129            "serialize name, description and externalDocs",
130        );
131
132        assert_eq!(
133            serde_json::to_value(Tag {
134                name: String::from("pet"),
135                description: Some(String::from("Pets operations")),
136                ..Default::default()
137            })
138            .unwrap(),
139            serde_json::json!({
140                "name": "pet",
141                "description":"Pets operations",
142            }),
143            "serialize name and description",
144        );
145
146        assert_eq!(
147            serde_json::to_value(Tag {
148                name: String::from("pet"),
149                ..Default::default()
150            })
151            .unwrap(),
152            serde_json::json!({
153                "name": "pet",
154            }),
155            "serialize name only",
156        );
157    }
158
159    #[test]
160    fn validate() {
161        let spec = Spec::default();
162        let mut ctx = Context::new(&spec, Default::default());
163        Tag {
164            name: String::from("pet"),
165            description: Some(String::from("Pets operations")),
166            external_docs: Some(ExternalDocumentation {
167                description: Some(String::from("Find more info here")),
168                url: String::from("https://example.com/about"),
169                ..Default::default()
170            }),
171            ..Default::default()
172        }
173        .validate_with_context(&mut ctx, String::from("tag"));
174        assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
175
176        Tag {
177            name: String::from("pet"),
178            description: Some(String::from("Pets operations")),
179            ..Default::default()
180        }
181        .validate_with_context(&mut ctx, String::from("tag"));
182        assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
183
184        Tag {
185            name: String::from("pet"),
186            ..Default::default()
187        }
188        .validate_with_context(&mut ctx, String::from("tag"));
189        assert!(ctx.errors.is_empty(), "no errors: {:?}", ctx.errors);
190
191        Tag {
192            ..Default::default()
193        }
194        .validate_with_context(&mut ctx, String::from("tag"));
195        assert_eq!(
196            ctx.errors,
197            vec!["tag.name: must not be empty"],
198            "name error: {:?}",
199            ctx.errors
200        );
201    }
202}