salvo_oapi/openapi/
request_body.rs1use indexmap::IndexMap;
5use serde::{Deserialize, Serialize};
6
7use super::{Content, Required};
8use crate::PropMap;
9
10#[non_exhaustive]
14#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
15#[serde(rename_all = "camelCase")]
16pub struct RequestBody {
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub description: Option<String>,
20
21 #[serde(rename = "content")]
23 pub contents: IndexMap<String, Content>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub required: Option<Required>,
28
29 #[serde(skip_serializing_if = "PropMap::is_empty", flatten)]
31 pub extensions: PropMap<String, serde_json::Value>,
32}
33
34impl RequestBody {
35 #[must_use]
38 pub fn new() -> Self {
39 Default::default()
40 }
41 #[must_use]
43 pub fn description<S: Into<String>>(mut self, description: S) -> Self {
44 self.description = Some(description.into());
45 self
46 }
47
48 #[must_use]
50 pub fn required(mut self, required: Required) -> Self {
51 self.required = Some(required);
52 self
53 }
54
55 #[must_use]
57 pub fn add_content<S: Into<String>, C: Into<Content>>(mut self, kind: S, content: C) -> Self {
58 self.contents.insert(kind.into(), content.into());
59 self
60 }
61
62 #[must_use]
64 pub fn extensions(mut self, extensions: PropMap<String, serde_json::Value>) -> Self {
65 self.extensions = extensions;
66 self
67 }
68
69 pub fn merge(&mut self, other: Self) {
71 let Self {
72 description,
73 contents,
74 required,
75 extensions,
76 } = other;
77 if let Some(description) = description
78 && !description.is_empty()
79 {
80 self.description = Some(description);
81 }
82 self.contents.extend(contents);
83 if let Some(required) = required {
84 self.required = Some(required);
85 }
86 self.extensions.extend(extensions);
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use assert_json_diff::assert_json_eq;
93 use serde_json::json;
94
95 use super::{Content, RequestBody, Required};
96
97 #[test]
98 fn request_body_new() {
99 let request_body = RequestBody::new();
100
101 assert!(request_body.contents.is_empty());
102 assert_eq!(request_body.description, None);
103 assert!(request_body.required.is_none());
104 }
105
106 #[test]
107 fn request_body_builder() -> Result<(), serde_json::Error> {
108 let request_body = RequestBody::new()
109 .description("A sample requestBody")
110 .required(Required::True)
111 .add_content(
112 "application/json",
113 Content::new(crate::Ref::from_schema_name("EmailPayload")),
114 );
115
116 assert_json_eq!(
117 request_body,
118 json!({
119 "description": "A sample requestBody",
120 "content": {
121 "application/json": {
122 "schema": {
123 "$ref": "#/components/schemas/EmailPayload"
124 }
125 }
126 },
127 "required": true
128 })
129 );
130 Ok(())
131 }
132
133 #[test]
134 fn request_body_merge() {
135 let mut request_body = RequestBody::new();
136 let other_request_body = RequestBody::new()
137 .description("Merged requestBody")
138 .required(Required::True)
139 .add_content(
140 "application/json",
141 Content::new(crate::Ref::from_schema_name("EmailPayload")),
142 );
143
144 request_body.merge(other_request_body);
145 assert_json_eq!(
146 request_body,
147 json!({
148 "description": "Merged requestBody",
149 "content": {
150 "application/json": {
151 "schema": {
152 "$ref": "#/components/schemas/EmailPayload"
153 }
154 }
155 },
156 "required": true
157 })
158 );
159 }
160}