utoipa/openapi/
request_body.rs1use std::collections::BTreeMap;
5
6use serde::{Deserialize, Serialize};
7
8use super::extensions::Extensions;
9use super::{builder, set_value, Content, Required};
10
11builder! {
12 RequestBodyBuilder;
13
14 #[non_exhaustive]
18 #[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
19 #[cfg_attr(feature = "debug", derive(Debug))]
20 #[serde(rename_all = "camelCase")]
21 pub struct RequestBody {
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub description: Option<String>,
25
26 pub content: BTreeMap<String, Content>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub required: Option<Required>,
32
33 #[serde(skip_serializing_if = "Option::is_none", flatten)]
35 pub extensions: Option<Extensions>,
36 }
37}
38
39impl RequestBody {
40 pub fn new() -> Self {
42 Default::default()
43 }
44}
45
46impl RequestBodyBuilder {
47 pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
49 set_value!(self description description.map(|description| description.into()))
50 }
51
52 pub fn required(mut self, required: Option<Required>) -> Self {
54 set_value!(self required required)
55 }
56
57 pub fn content<S: Into<String>>(mut self, content_type: S, content: Content) -> Self {
59 self.content.insert(content_type.into(), content);
60
61 self
62 }
63
64 pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
66 set_value!(self extensions extensions)
67 }
68}
69
70#[cfg(feature = "openapi_extensions")]
99#[cfg_attr(doc_cfg, doc(cfg(feature = "openapi_extensions")))]
100pub trait RequestBodyExt {
101 fn json_schema_ref(self, ref_name: &str) -> Self;
104}
105
106#[cfg(feature = "openapi_extensions")]
107impl RequestBodyExt for RequestBody {
108 fn json_schema_ref(mut self, ref_name: &str) -> RequestBody {
109 self.content.insert(
110 "application/json".to_string(),
111 crate::openapi::Content::new(Some(crate::openapi::Ref::from_schema_name(ref_name))),
112 );
113 self
114 }
115}
116
117#[cfg(feature = "openapi_extensions")]
118impl RequestBodyExt for RequestBodyBuilder {
119 fn json_schema_ref(self, ref_name: &str) -> RequestBodyBuilder {
120 self.content(
121 "application/json",
122 crate::openapi::Content::new(Some(crate::openapi::Ref::from_schema_name(ref_name))),
123 )
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::{Content, RequestBody, RequestBodyBuilder, Required};
130 use insta::assert_json_snapshot;
131
132 #[test]
133 fn request_body_new() {
134 let request_body = RequestBody::new();
135
136 assert!(request_body.content.is_empty());
137 assert_eq!(request_body.description, None);
138 assert!(request_body.required.is_none());
139 }
140
141 #[test]
142 fn request_body_builder() {
143 let request_body = RequestBodyBuilder::new()
144 .description(Some("A sample requestBody"))
145 .required(Some(Required::True))
146 .content(
147 "application/json",
148 Content::new(Some(crate::openapi::Ref::from_schema_name("EmailPayload"))),
149 )
150 .build();
151 assert_json_snapshot!(request_body);
152 }
153}
154
155#[cfg(all(test, feature = "openapi_extensions"))]
156#[cfg_attr(doc_cfg, doc(cfg(feature = "openapi_extensions")))]
157mod openapi_extensions_tests {
158 use crate::openapi::request_body::RequestBodyBuilder;
159 use insta::assert_json_snapshot;
160
161 use super::RequestBodyExt;
162
163 #[test]
164 fn request_body_ext() {
165 let request_body = RequestBodyBuilder::new()
166 .build()
167 .json_schema_ref("EmailPayload");
169 assert_json_snapshot!(request_body);
170 }
171
172 #[test]
173 fn request_body_builder_ext() {
174 let request_body = RequestBodyBuilder::new()
175 .json_schema_ref("EmailPayload")
176 .build();
177 assert_json_snapshot!(request_body);
178 }
179}