utoipa/openapi/
request_body.rs1use std::collections::BTreeMap;
5
6use serde::{Deserialize, Serialize};
7
8use super::{builder, set_value, Content, Required};
9
10builder! {
11 RequestBodyBuilder;
12
13 #[non_exhaustive]
17 #[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
18 #[cfg_attr(feature = "debug", derive(Debug))]
19 #[serde(rename_all = "camelCase")]
20 pub struct RequestBody {
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub description: Option<String>,
24
25 pub content: BTreeMap<String, Content>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub required: Option<Required>,
31 }
32}
33
34impl RequestBody {
35 pub fn new() -> Self {
37 Default::default()
38 }
39}
40
41impl RequestBodyBuilder {
42 pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
44 set_value!(self description description.map(|description| description.into()))
45 }
46
47 pub fn required(mut self, required: Option<Required>) -> Self {
49 set_value!(self required required)
50 }
51
52 pub fn content<S: Into<String>>(mut self, content_type: S, content: Content) -> Self {
54 self.content.insert(content_type.into(), content);
55
56 self
57 }
58}
59
60#[cfg(feature = "openapi_extensions")]
89#[cfg_attr(doc_cfg, doc(cfg(feature = "openapi_extensions")))]
90pub trait RequestBodyExt {
91 fn json_schema_ref(self, ref_name: &str) -> Self;
94}
95
96#[cfg(feature = "openapi_extensions")]
97impl RequestBodyExt for RequestBody {
98 fn json_schema_ref(mut self, ref_name: &str) -> RequestBody {
99 self.content.insert(
100 "application/json".to_string(),
101 crate::openapi::Content::new(crate::openapi::Ref::from_schema_name(ref_name)),
102 );
103 self
104 }
105}
106
107#[cfg(feature = "openapi_extensions")]
108impl RequestBodyExt for RequestBodyBuilder {
109 fn json_schema_ref(self, ref_name: &str) -> RequestBodyBuilder {
110 self.content(
111 "application/json",
112 crate::openapi::Content::new(crate::openapi::Ref::from_schema_name(ref_name)),
113 )
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use assert_json_diff::assert_json_eq;
120 use serde_json::json;
121
122 use super::{Content, RequestBody, RequestBodyBuilder, Required};
123
124 #[test]
125 fn request_body_new() {
126 let request_body = RequestBody::new();
127
128 assert!(request_body.content.is_empty());
129 assert_eq!(request_body.description, None);
130 assert!(request_body.required.is_none());
131 }
132
133 #[test]
134 fn request_body_builder() -> Result<(), serde_json::Error> {
135 let request_body = RequestBodyBuilder::new()
136 .description(Some("A sample requestBody"))
137 .required(Some(Required::True))
138 .content(
139 "application/json",
140 Content::new(crate::openapi::Ref::from_schema_name("EmailPayload")),
141 )
142 .build();
143 let serialized = serde_json::to_string_pretty(&request_body)?;
144 println!("serialized json:\n {serialized}");
145 assert_json_eq!(
146 request_body,
147 json!({
148 "description": "A sample requestBody",
149 "content": {
150 "application/json": {
151 "schema": {
152 "$ref": "#/components/schemas/EmailPayload"
153 }
154 }
155 },
156 "required": true
157 })
158 );
159 Ok(())
160 }
161}
162
163#[cfg(all(test, feature = "openapi_extensions"))]
164#[cfg_attr(doc_cfg, doc(cfg(feature = "openapi_extensions")))]
165mod openapi_extensions_tests {
166 use assert_json_diff::assert_json_eq;
167 use serde_json::json;
168
169 use crate::openapi::request_body::RequestBodyBuilder;
170
171 use super::RequestBodyExt;
172
173 #[test]
174 fn request_body_ext() {
175 let request_body = RequestBodyBuilder::new()
176 .build()
177 .json_schema_ref("EmailPayload");
179 assert_json_eq!(
180 request_body,
181 json!({
182 "content": {
183 "application/json": {
184 "schema": {
185 "$ref": "#/components/schemas/EmailPayload"
186 }
187 }
188 }
189 })
190 );
191 }
192
193 #[test]
194 fn request_body_builder_ext() {
195 let request_body = RequestBodyBuilder::new()
196 .json_schema_ref("EmailPayload")
197 .build();
198 assert_json_eq!(
199 request_body,
200 json!({
201 "content": {
202 "application/json": {
203 "schema": {
204 "$ref": "#/components/schemas/EmailPayload"
205 }
206 }
207 }
208 })
209 );
210 }
211}