utoipa/openapi/content.rs
1//! Implements content object for request body and response.
2use std::collections::BTreeMap;
3
4use serde::{Deserialize, Serialize};
5
6use serde_json::Value;
7
8use super::builder;
9use super::example::Example;
10use super::extensions::Extensions;
11use super::{encoding::Encoding, set_value, RefOr, Schema};
12
13builder! {
14 ContentBuilder;
15
16
17 /// Content holds request body content or response content.
18 ///
19 /// [`Content`] implements OpenAPI spec [Media Type Object][media_type]
20 ///
21 /// [media_type]: <https://spec.openapis.org/oas/latest.html#media-type-object>
22 #[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
23 #[cfg_attr(feature = "debug", derive(Debug))]
24 #[non_exhaustive]
25 pub struct Content {
26 /// Schema used in response body or request body.
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub schema: Option<RefOr<Schema>>,
29
30 /// Example for request body or response body.
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub example: Option<Value>,
33
34 /// Examples of the request body or response body. [`Content::examples`] should match to
35 /// media type and specified schema if present. [`Content::examples`] and
36 /// [`Content::example`] are mutually exclusive. If both are defined `examples` will
37 /// override value in `example`.
38 #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
39 pub examples: BTreeMap<String, RefOr<Example>>,
40
41 /// A map between a property name and its encoding information.
42 ///
43 /// The key, being the property name, MUST exist in the [`Content::schema`] as a property, with
44 /// `schema` being a [`Schema::Object`] and this object containing the same property key in
45 /// [`Object::properties`](crate::openapi::schema::Object::properties).
46 ///
47 /// The encoding object SHALL only apply to `request_body` objects when the media type is
48 /// multipart or `application/x-www-form-urlencoded`.
49 #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
50 pub encoding: BTreeMap<String, Encoding>,
51
52 /// Optional extensions "x-something".
53 #[serde(skip_serializing_if = "Option::is_none", flatten)]
54 pub extensions: Option<Extensions>,
55 }
56}
57
58impl Content {
59 /// Construct a new [`Content`] object for provided _`schema`_.
60 pub fn new<I: Into<RefOr<Schema>>>(schema: Option<I>) -> Self {
61 Self {
62 schema: schema.map(|schema| schema.into()),
63 ..Self::default()
64 }
65 }
66}
67
68impl ContentBuilder {
69 /// Add schema.
70 pub fn schema<I: Into<RefOr<Schema>>>(mut self, schema: Option<I>) -> Self {
71 set_value!(self schema schema.map(|schema| schema.into()))
72 }
73
74 /// Add example of schema.
75 pub fn example(mut self, example: Option<Value>) -> Self {
76 set_value!(self example example)
77 }
78
79 /// Add iterator of _`(N, V)`_ where `N` is name of example and `V` is [`Example`][example] to
80 /// [`Content`] of a request body or response body.
81 ///
82 /// [`Content::examples`] and [`Content::example`] are mutually exclusive. If both are defined
83 /// `examples` will override value in `example`.
84 ///
85 /// [example]: ../example/Example.html
86 pub fn examples_from_iter<
87 E: IntoIterator<Item = (N, V)>,
88 N: Into<String>,
89 V: Into<RefOr<Example>>,
90 >(
91 mut self,
92 examples: E,
93 ) -> Self {
94 self.examples.extend(
95 examples
96 .into_iter()
97 .map(|(name, example)| (name.into(), example.into())),
98 );
99
100 self
101 }
102
103 /// Add an encoding.
104 ///
105 /// The `property_name` MUST exist in the [`Content::schema`] as a property,
106 /// with `schema` being a [`Schema::Object`] and this object containing the same property
107 /// key in [`Object::properties`](crate::openapi::schema::Object::properties).
108 ///
109 /// The encoding object SHALL only apply to `request_body` objects when the media type is
110 /// multipart or `application/x-www-form-urlencoded`.
111 pub fn encoding<S: Into<String>, E: Into<Encoding>>(
112 mut self,
113 property_name: S,
114 encoding: E,
115 ) -> Self {
116 self.encoding.insert(property_name.into(), encoding.into());
117 self
118 }
119
120 /// Add openapi extensions (x-something) of the API.
121 pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
122 set_value!(self extensions extensions)
123 }
124}