openapiv3/
paths.rs

1use std::marker::PhantomData;
2
3use crate::*;
4use indexmap::IndexMap;
5use serde::{Deserialize, Deserializer, Serialize};
6
7/// Describes the operations available on a single path.
8/// A Path Item MAY be empty, due to ACL constraints.
9/// The path itself is still exposed to the documentation
10/// viewer but they will not know which operations and
11/// parameters are available.
12#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
13pub struct PathItem {
14    /// An optional, string summary, intended to apply to all operations in
15    /// this path.
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub summary: Option<String>,
18    /// An optional, string description, intended to apply to all operations in
19    /// this path. CommonMark syntax MAY be used for rich text representation.
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub description: Option<String>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub get: Option<Operation>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub put: Option<Operation>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub post: Option<Operation>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub delete: Option<Operation>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub options: Option<Operation>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub head: Option<Operation>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub patch: Option<Operation>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub trace: Option<Operation>,
38    /// An alternative server array to service all operations in this path.
39    #[serde(default, skip_serializing_if = "Vec::is_empty")]
40    pub servers: Vec<Server>,
41    /// A list of parameters that are applicable for all the
42    /// operations described under this path. These parameters
43    /// can be overridden at the operation level, but cannot be
44    /// removed there. The list MUST NOT include duplicated parameters.
45    /// A unique parameter is defined by a combination of a name and location.
46    /// The list can use the Reference Object to link to parameters that
47    /// are defined at the OpenAPI Object's components/parameters.
48    #[serde(default)]
49    #[serde(skip_serializing_if = "Vec::is_empty")]
50    pub parameters: Vec<ReferenceOr<Parameter>>,
51    /// Inline extensions to this object.
52    #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
53    pub extensions: IndexMap<String, serde_json::Value>,
54}
55
56impl PathItem {
57    /// Returns an iterator of references to the [Operation]s in the [PathItem].
58    pub fn iter(&self) -> impl Iterator<Item = (&str, &'_ Operation)> {
59        vec![
60            ("get", &self.get),
61            ("put", &self.put),
62            ("post", &self.post),
63            ("delete", &self.delete),
64            ("options", &self.options),
65            ("head", &self.head),
66            ("patch", &self.patch),
67            ("trace", &self.trace),
68        ]
69        .into_iter()
70        .filter_map(|(method, maybe_op)| maybe_op.as_ref().map(|op| (method, op)))
71    }
72}
73
74impl IntoIterator for PathItem {
75    type Item = (&'static str, Operation);
76
77    type IntoIter = std::vec::IntoIter<Self::Item>;
78
79    /// Returns an iterator of the [Operation]s in the [PathItem].
80    fn into_iter(self) -> Self::IntoIter {
81        vec![
82            ("get", self.get),
83            ("put", self.put),
84            ("post", self.post),
85            ("delete", self.delete),
86            ("options", self.options),
87            ("head", self.head),
88            ("patch", self.patch),
89            ("trace", self.trace),
90        ]
91        .into_iter()
92        .filter_map(|(method, maybe_op)| maybe_op.map(|op| (method, op)))
93        .collect::<Vec<_>>()
94        .into_iter()
95    }
96}
97
98/// Holds the relative paths to the individual endpoints and
99/// their operations. The path is appended to the URL from the
100/// Server Object in order to construct the full URL. The Paths
101/// MAY be empty, due to ACL constraints.
102#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
103pub struct Paths {
104    /// A map of PathItems or references to them.
105    #[serde(flatten, deserialize_with = "deserialize_paths")]
106    pub paths: IndexMap<String, ReferenceOr<PathItem>>,
107    /// Inline extensions to this object.
108    #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
109    pub extensions: IndexMap<String, serde_json::Value>,
110}
111
112impl Paths {
113    /// Iterate over path items.
114    pub fn iter(&self) -> indexmap::map::Iter<String, ReferenceOr<PathItem>> {
115        self.paths.iter()
116    }
117}
118
119impl IntoIterator for Paths {
120    type Item = (String, ReferenceOr<PathItem>);
121
122    type IntoIter = indexmap::map::IntoIter<String, ReferenceOr<PathItem>>;
123
124    fn into_iter(self) -> Self::IntoIter {
125        self.paths.into_iter()
126    }
127}
128
129fn deserialize_paths<'de, D>(
130    deserializer: D,
131) -> Result<IndexMap<String, ReferenceOr<PathItem>>, D::Error>
132where
133    D: Deserializer<'de>,
134{
135    deserializer.deserialize_map(PredicateVisitor(
136        |key: &String| key.starts_with('/'),
137        PhantomData,
138    ))
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn test_path_item_iterators() {
147        let operation = Operation::default();
148
149        let path_item = PathItem {
150            get: Some(operation.clone()),
151            post: Some(operation.clone()),
152            delete: Some(operation.clone()),
153            ..Default::default()
154        };
155
156        let expected = vec![
157            ("get", &operation),
158            ("post", &operation),
159            ("delete", &operation),
160        ];
161        assert_eq!(path_item.iter().collect::<Vec<_>>(), expected);
162
163        let expected = vec![
164            ("get", operation.clone()),
165            ("post", operation.clone()),
166            ("delete", operation.clone()),
167        ];
168        assert_eq!(path_item.into_iter().collect::<Vec<_>>(), expected);
169    }
170}