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
//! Implements content object for request body and response.
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::builder;
use super::example::Example;
use super::extensions::Extensions;
use super::{encoding::Encoding, set_value, RefOr, Schema};
builder! {
ContentBuilder;
/// Content holds request body content or response content.
///
/// [`Content`] implements OpenAPI spec [Media Type Object][media_type]
///
/// [media_type]: <https://spec.openapis.org/oas/latest.html#media-type-object>
#[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct Content {
/// Schema used in response body or request body.
#[serde(skip_serializing_if = "Option::is_none")]
pub schema: Option<RefOr<Schema>>,
/// Schema used for each item in a streaming or event-based media type.
#[serde(skip_serializing_if = "Option::is_none")]
pub item_schema: Option<RefOr<Schema>>,
/// Description of this media type. Markdown syntax is supported.
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// Example for request body or response body.
#[serde(skip_serializing_if = "Option::is_none")]
pub example: Option<Value>,
/// Examples of the request body or response body. [`Content::examples`] should match to
/// media type and specified schema if present. [`Content::examples`] and
/// [`Content::example`] are mutually exclusive. If both are defined `examples` will
/// override value in `example`.
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
pub examples: BTreeMap<String, RefOr<Example>>,
/// A map between a property name and its encoding information.
///
/// The key, being the property name, MUST exist in the [`Content::schema`] as a property, with
/// `schema` being a [`Schema::Object`] and this object containing the same property key in
/// [`Object::properties`](crate::openapi::schema::Object::properties).
///
/// The encoding object SHALL only apply to `request_body` objects when the media type is
/// multipart or `application/x-www-form-urlencoded`.
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
pub encoding: BTreeMap<String, Encoding>,
/// Encoding information for tuple-like sequential or array items.
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub prefix_encoding: Vec<Encoding>,
/// Encoding information for each item in a sequential or array media type.
#[serde(skip_serializing_if = "Option::is_none")]
pub item_encoding: Option<Box<Encoding>>,
/// Optional extensions "x-something".
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<Extensions>,
}
}
impl Content {
/// Construct a new [`Content`] object for provided _`schema`_.
pub fn new<I: Into<RefOr<Schema>>>(schema: Option<I>) -> Self {
Self {
schema: schema.map(|schema| schema.into()),
..Self::default()
}
}
}
impl ContentBuilder {
/// Add schema.
pub fn schema<I: Into<RefOr<Schema>>>(mut self, schema: Option<I>) -> Self {
set_value!(self schema schema.map(|schema| schema.into()))
}
/// Add item schema for a streaming or event-based media type.
pub fn item_schema<I: Into<RefOr<Schema>>>(mut self, item_schema: Option<I>) -> Self {
set_value!(self item_schema item_schema.map(|schema| schema.into()))
}
/// Add or change description of this media type.
pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
set_value!(self description description.map(Into::into))
}
/// Add example of schema.
pub fn example(mut self, example: Option<Value>) -> Self {
set_value!(self example example)
}
/// Add iterator of _`(N, V)`_ where `N` is name of example and `V` is [`Example`][example] to
/// [`Content`] of a request body or response body.
///
/// [`Content::examples`] and [`Content::example`] are mutually exclusive. If both are defined
/// `examples` will override value in `example`.
///
/// [example]: ../example/Example.html
pub fn examples_from_iter<
E: IntoIterator<Item = (N, V)>,
N: Into<String>,
V: Into<RefOr<Example>>,
>(
mut self,
examples: E,
) -> Self {
self.examples.extend(
examples
.into_iter()
.map(|(name, example)| (name.into(), example.into())),
);
self
}
/// Add an encoding.
///
/// The `property_name` MUST exist in the [`Content::schema`] as a property,
/// with `schema` being a [`Schema::Object`] and this object containing the same property
/// key in [`Object::properties`](crate::openapi::schema::Object::properties).
///
/// The encoding object SHALL only apply to `request_body` objects when the media type is
/// multipart or `application/x-www-form-urlencoded`.
pub fn encoding<S: Into<String>, E: Into<Encoding>>(
mut self,
property_name: S,
encoding: E,
) -> Self {
self.encoding.insert(property_name.into(), encoding.into());
self
}
/// Add encoding information for tuple-like sequential or array items.
pub fn prefix_encoding<I: IntoIterator<Item = E>, E: Into<Encoding>>(
mut self,
prefix_encoding: I,
) -> Self {
set_value!(self prefix_encoding prefix_encoding.into_iter().map(Into::into).collect())
}
/// Add encoding information for each item in a sequential or array media type.
pub fn item_encoding<E: Into<Encoding>>(mut self, item_encoding: Option<E>) -> Self {
set_value!(self item_encoding item_encoding.map(|encoding| Box::new(encoding.into())))
}
/// Add openapi extensions (x-something) of the API.
pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
set_value!(self extensions extensions)
}
}
impl From<ContentBuilder> for RefOr<Content> {
fn from(content_builder: ContentBuilder) -> Self {
Self::T(content_builder.build())
}
}
impl From<super::Ref> for RefOr<Content> {
fn from(r: super::Ref) -> Self {
Self::Ref(r)
}
}