salvo_oapi/openapi/components.rs
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
//! Implements [OpenAPI Schema Object][schema] types which can be
//! used to define field properties, enum values, array or object types.
//!
//! [schema]: https://spec.openapis.org/oas/latest.html#schema-object
use serde::{Deserialize, Serialize};
use crate::{PropMap, RefOr, Response, Responses, Schema, Schemas, SecurityScheme};
/// Implements [OpenAPI Components Object][components] which holds supported
/// reusable objects.
///
/// Components can hold either reusable types themselves or references to other reusable
/// types.
///
/// [components]: https://spec.openapis.org/oas/latest.html#components-object
#[non_exhaustive]
#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Components {
/// Map of reusable [OpenAPI Schema Object][schema]s.
///
/// [schema]: https://spec.openapis.org/oas/latest.html#schema-object
#[serde(skip_serializing_if = "PropMap::is_empty", default)]
pub schemas: Schemas,
/// Map of reusable response name, to [OpenAPI Response Object][response]s or [OpenAPI
/// Reference][reference]s to [OpenAPI Response Object][response]s.
///
/// [response]: https://spec.openapis.org/oas/latest.html#response-object
/// [reference]: https://spec.openapis.org/oas/latest.html#reference-object
#[serde(skip_serializing_if = "PropMap::is_empty", default)]
pub responses: Responses,
/// Map of reusable [OpenAPI Security Scheme Object][security_scheme]s.
///
/// [security_scheme]: https://spec.openapis.org/oas/latest.html#security-scheme-object
#[serde(skip_serializing_if = "PropMap::is_empty", default)]
pub security_schemes: PropMap<String, SecurityScheme>,
}
impl Components {
/// Construct a new empty [`Components`]. This is effectively same as calling [`Components::default`].
pub fn new() -> Self {
Default::default()
}
/// Add [`SecurityScheme`] to [`Components`] and returns `Self`.
///
/// Accepts two arguments where first is the name of the [`SecurityScheme`]. This is later when
/// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecurityScheme`].
///
/// [requirement]: crate::SecurityRequirement
pub fn add_security_scheme<N: Into<String>, S: Into<SecurityScheme>>(
mut self,
name: N,
security_scheme: S,
) -> Self {
self.security_schemes
.insert(name.into(), security_scheme.into());
self
}
/// Add iterator of [`SecurityScheme`]s to [`Components`].
///
/// Accepts two arguments where first is the name of the [`SecurityScheme`]. This is later when
/// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecurityScheme`].
///
/// [requirement]: crate::SecurityRequirement
pub fn extend_security_schemes<
I: IntoIterator<Item = (N, S)>,
N: Into<String>,
S: Into<SecurityScheme>,
>(
mut self,
schemas: I,
) -> Self {
self.security_schemes.extend(
schemas
.into_iter()
.map(|(name, item)| (name.into(), item.into())),
);
self
}
/// Add [`Schema`] to [`Components`] and returns `Self`.
///
/// Accepts two arguments where first is name of the schema and second is the schema itself.
pub fn add_schema<S: Into<String>, I: Into<RefOr<Schema>>>(
mut self,
name: S,
schema: I,
) -> Self {
self.schemas.insert(name, schema);
self
}
/// Add [`Schema`]s from iterator.
///
/// # Examples
/// ```
/// # use salvo_oapi::{Components, Object, BasicType, Schema};
/// Components::new().extend_schemas([(
/// "Pet",
/// Schema::from(
/// Object::new()
/// .property(
/// "name",
/// Object::new().schema_type(BasicType::String),
/// )
/// .required("name")
/// ),
/// )]);
/// ```
pub fn extend_schemas<I, C, S>(mut self, schemas: I) -> Self
where
I: IntoIterator<Item = (S, C)>,
C: Into<RefOr<Schema>>,
S: Into<String>,
{
self.schemas.extend(
schemas
.into_iter()
.map(|(name, schema)| (name.into(), schema.into())),
);
self
}
/// Add a new response and returns `self`.
pub fn response<S: Into<String>, R: Into<RefOr<Response>>>(
mut self,
name: S,
response: R,
) -> Self {
self.responses.insert(name.into(), response.into());
self
}
/// Extends responses with the contents of an iterator.
pub fn extend_responses<
I: IntoIterator<Item = (S, R)>,
S: Into<String>,
R: Into<RefOr<Response>>,
>(
mut self,
responses: I,
) -> Self {
self.responses.extend(
responses
.into_iter()
.map(|(name, response)| (name.into(), response.into())),
);
self
}
/// 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 Components) {
other
.schemas
.retain(|name, _| !self.schemas.contains_key(name));
self.schemas.append(&mut other.schemas);
other
.responses
.retain(|name, _| !self.responses.contains_key(name));
self.responses.append(&mut other.responses);
other
.security_schemes
.retain(|name, _| !self.security_schemes.contains_key(name));
self.security_schemes.append(&mut other.security_schemes);
}
/// Returns `true` if instance contains no elements.
pub fn is_empty(&self) -> bool {
self.schemas.is_empty() && self.responses.is_empty() && self.security_schemes.is_empty()
}
}