1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
//! Implements [OpenAPI Path Object][paths] types.
//!
//! [paths]: https://spec.openapis.org/oas/latest.html#paths-object
use std::collections::BTreeMap;
use std::iter;
use std::ops::{Deref, DerefMut};
use serde::{Deserialize, Serialize};
use super::{Operation, Operations, Parameter, Parameters, Server, Servers};
/// Implements [OpenAPI Path Object][paths] types.
///
/// [paths]: https://spec.openapis.org/oas/latest.html#paths-object
#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Debug)]
pub struct Paths(BTreeMap<String, PathItem>);
impl Deref for Paths {
type Target = BTreeMap<String, PathItem>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Paths {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Paths {
/// Construct a new empty [`Paths`]. This is effectively same as calling [`Paths::default`].
pub fn new() -> Self {
Default::default()
}
/// Inserts a key-value pair into the instance and returns `self`.
pub fn path<K: Into<String>, V: Into<PathItem>>(mut self, key: K, value: V) -> Self {
self.insert(key, value);
self
}
/// Inserts a key-value pair into the instance.
pub fn insert<K: Into<String>, V: Into<PathItem>>(&mut self, key: K, value: V) {
let key = key.into();
let mut value = value.into();
self.0
.entry(key)
.and_modify(|item| {
if value.summary.is_some() {
item.summary = value.summary.take();
}
if value.description.is_some() {
item.description = value.description.take();
}
item.servers.append(&mut value.servers);
item.parameters.append(&mut value.parameters);
item.operations.append(&mut value.operations);
})
.or_insert(value);
}
/// Moves all elements from `other` into `self`, leaving `other` empty.
///
/// If a key from `other` is already present in `self`, the respective
/// value from `self` will be overwritten with the respective value from `other`.
pub fn append(&mut self, other: &mut Paths) {
let items = std::mem::take(&mut other.0);
for item in items {
self.insert(item.0, item.1);
}
}
/// Extends a collection with the contents of an iterator.
pub fn extend<I, K, V>(&mut self, iter: I)
where
I: IntoIterator<Item = (K, V)>,
K: Into<String>,
V: Into<PathItem>,
{
for (k, v) in iter.into_iter() {
self.insert(k, v);
}
}
}
/// Implements [OpenAPI Path Item Object][path_item] what describes [`Operation`]s available on
/// a single path.
///
/// [path_item]: https://spec.openapis.org/oas/latest.html#path-item-object
#[non_exhaustive]
#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PathItem {
/// Optional summary intended to apply all operations in this [`PathItem`].
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
/// Optional description intended to apply all operations in this [`PathItem`].
/// Description supports markdown syntax.
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// Alternative [`Server`] array to serve all [`Operation`]s in this [`PathItem`] overriding
/// the global server array.
#[serde(skip_serializing_if = "Servers::is_empty")]
pub servers: Servers,
/// List of [`Parameter`]s common to all [`Operation`]s in this [`PathItem`]. Parameters cannot
/// contain duplicate parameters. They can be overridden in [`Operation`] level but cannot be
/// removed there.
#[serde(skip_serializing_if = "Parameters::is_empty")]
#[serde(flatten)]
pub parameters: Parameters,
/// Map of operations in this [`PathItem`]. Operations can hold only one operation
/// per [`PathItemType`].
#[serde(flatten)]
pub operations: Operations,
}
impl PathItem {
/// Construct a new [`PathItem`] with provided [`Operation`] mapped to given [`PathItemType`].
pub fn new<O: Into<Operation>>(path_item_type: PathItemType, operation: O) -> Self {
let operations = BTreeMap::from_iter(iter::once((path_item_type, operation.into())));
Self {
operations: Operations(operations),
..Default::default()
}
}
/// Moves all elements from `other` into `self`, leaving `other` empty.
///
/// If a key from `other` is already present in `self`, the respective
/// value from `self` will be overwritten with the respective value from `other`.
pub fn append(&mut self, other: &mut Self) {
self.operations.append(&mut other.operations);
self.servers.append(&mut other.servers);
self.parameters.append(&mut other.parameters);
if other.description.is_none() {
self.description = other.description.take();
}
if other.summary.is_some() {
self.summary = other.summary.take();
}
}
/// Append a new [`Operation`] by [`PathItemType`] to this [`PathItem`]. Operations can
/// hold only one operation per [`PathItemType`].
pub fn add_operation<O: Into<Operation>>(mut self, path_item_type: PathItemType, operation: O) -> Self {
self.operations.insert(path_item_type, operation.into());
self
}
/// Add or change summary intended to apply all operations in this [`PathItem`].
pub fn summary<S: Into<String>>(mut self, summary: S) -> Self {
self.summary = Some(summary.into());
self
}
/// Add or change optional description intended to apply all operations in this [`PathItem`].
/// Description supports markdown syntax.
pub fn description<S: Into<String>>(mut self, description: S) -> Self {
self.description = Some(description.into());
self
}
/// Add list of alternative [`Server`]s to serve all [`Operation`]s in this [`PathItem`] overriding
/// the global server array.
pub fn servers<I: IntoIterator<Item = Server>>(mut self, servers: I) -> Self {
self.servers = Servers(servers.into_iter().collect());
self
}
/// Append list of [`Parameter`]s common to all [`Operation`]s to this [`PathItem`].
pub fn parameters<I: IntoIterator<Item = Parameter>>(mut self, parameters: I) -> Self {
self.parameters = Parameters(parameters.into_iter().collect());
self
}
}
/// Path item operation type.
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy, Debug)]
#[serde(rename_all = "lowercase")]
pub enum PathItemType {
/// Type mapping for HTTP _GET_ request.
Get,
/// Type mapping for HTTP _POST_ request.
Post,
/// Type mapping for HTTP _PUT_ request.
Put,
/// Type mapping for HTTP _DELETE_ request.
Delete,
/// Type mapping for HTTP _OPTIONS_ request.
Options,
/// Type mapping for HTTP _HEAD_ request.
Head,
/// Type mapping for HTTP _PATCH_ request.
Patch,
/// Type mapping for HTTP _TRACE_ request.
Trace,
/// Type mapping for HTTP _CONNECT_ request.
Connect,
}