1use crate::*;
2use indexmap::IndexMap;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
7#[serde(rename_all = "camelCase")]
8pub struct Operation {
9 #[serde(default)]
13 #[serde(skip_serializing_if = "Vec::is_empty")]
14 pub tags: Vec<String>,
15 #[serde(skip_serializing_if = "Option::is_none")]
17 pub summary: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
21 pub description: Option<String>,
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub external_docs: Option<ExternalDocumentation>,
25 #[serde(skip_serializing_if = "Option::is_none")]
31 pub operation_id: Option<String>,
32 #[serde(default)]
40 #[serde(skip_serializing_if = "Vec::is_empty")]
41 pub parameters: Vec<RefOr<Parameter>>,
42 #[serde(skip_serializing_if = "Option::is_none")]
48 pub request_body: Option<RefOr<RequestBody>>,
49 pub responses: Responses,
52 #[serde(default, skip_serializing_if = "is_false")]
54 pub deprecated: bool,
55 #[serde(default)]
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub security: Option<Vec<SecurityRequirement>>,
63 #[serde(default)]
67 #[serde(skip_serializing_if = "Vec::is_empty")]
68 pub servers: Vec<Server>,
69 #[serde(flatten, deserialize_with = "crate::util::deserialize_extensions")]
71 pub extensions: IndexMap<String, serde_json::Value>,
72}
73
74impl Operation {
75 pub fn add_response_error_json(&mut self, status: u16, message: String) {
76 let status_code_enum = StatusCode::Code(status);
77 self.responses.responses.insert(
78 status_code_enum, RefOr::Item(Response {
80 description: message,
81 content: IndexMap::new(),
82 ..Response::default()
83 }),
84 );
85 }
86
87 pub fn add_response_success_json(&mut self, schema: Option<RefOr<Schema>>) {
88 self.responses.responses.insert(
89 StatusCode::Code(200),
90 RefOr::Item({
91 let mut content = indexmap::IndexMap::new();
92 content.insert(
93 "application/json".to_string(),
94 MediaType {
95 schema,
96 ..MediaType::default()
97 },
98 );
99 Response {
100 description: "OK".to_string(),
101 content,
102 ..Response::default()
103 }
104 }),
105 );
106 }
107
108 pub fn add_request_body_json(&mut self, schema: Option<RefOr<Schema>>) {
109 let mut content = indexmap::IndexMap::new();
110 content.insert(
111 "application/json".to_string(),
112 MediaType {
113 schema,
114 ..MediaType::default()
115 },
116 );
117 self.request_body = Some(RefOr::Item(RequestBody {
118 content,
119 required: true,
120 ..RequestBody::default()
121 }));
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use crate::{Operation, RefOr, Responses, Schema, StatusCode};
128 use indexmap::IndexMap;
129 use serde_yaml::from_str;
130
131 #[test]
132 fn deserialize_responses() {
133 assert_eq!(
134 Operation {
135 responses: Responses {
136 default: None,
137 responses: {
138 let mut map = IndexMap::new();
139 map.insert(StatusCode::Code(200), RefOr::ref_("test"));
140 map
141 },
142 ..Default::default()
143 },
144 ..Default::default()
145 },
146 from_str("{ responses: { 200: { $ref: 'test' } } }").unwrap(),
147 );
148
149 assert_eq!(
150 Operation {
151 responses: Responses {
152 default: None,
153 responses: {
154 let mut map = IndexMap::new();
155 map.insert(StatusCode::Code(666), RefOr::ref_("demo"));
156 map
157 },
158 ..Default::default()
159 },
160 ..Default::default()
161 },
162 from_str("{ responses: { \"666\": { $ref: 'demo' } } }").unwrap(),
163 );
164
165 assert_eq!(
166 Operation {
167 responses: Responses {
168 default: Some(RefOr::ref_("def")),
169 responses: {
170 let mut map = IndexMap::new();
171 map.insert(StatusCode::Code(666), RefOr::ref_("demo"));
172 map.insert(StatusCode::Code(418), RefOr::ref_("demo"));
173 map
174 },
175 ..Default::default()
176 },
177 ..Default::default()
178 },
179 from_str("{ responses: { default: { $ref: 'def' }, \"666\": { $ref: 'demo' }, 418: { $ref: 'demo' } } }").unwrap(),
180 );
181 }
182
183 #[test]
184 fn test_basic() {
185 let mut op = Operation::default();
186 op.add_request_body_json(Some(RefOr::Item(Schema::new_string())));
187 }
188}