1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11#[cfg(feature = "di")]
12use crate::di::ResolvedDependencies;
13#[cfg(feature = "di")]
14use bytes::Bytes;
15
16#[derive(Debug, Clone)]
27pub struct RequestData {
28 pub path_params: Arc<HashMap<String, String>>,
30 pub query_params: Value,
32 pub validated_params: Option<Value>,
34 pub raw_query_params: Arc<HashMap<String, Vec<String>>>,
36 pub body: Value,
38 #[cfg(feature = "di")]
40 pub raw_body: Option<Bytes>,
41 #[cfg(not(feature = "di"))]
42 pub raw_body: Option<Vec<u8>>,
43 pub headers: Arc<HashMap<String, String>>,
45 pub cookies: Arc<HashMap<String, String>>,
47 pub method: String,
49 pub path: String,
51 #[cfg(feature = "di")]
53 pub dependencies: Option<Arc<ResolvedDependencies>>,
54}
55
56impl Serialize for RequestData {
57 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58 where
59 S: serde::Serializer,
60 {
61 use serde::ser::SerializeStruct;
62 let mut state = serializer.serialize_struct("RequestData", 10)?;
63 state.serialize_field("path_params", &*self.path_params)?;
64 state.serialize_field("query_params", &self.query_params)?;
65 state.serialize_field("validated_params", &self.validated_params)?;
66 state.serialize_field("raw_query_params", &*self.raw_query_params)?;
67 state.serialize_field("body", &self.body)?;
68 #[cfg(feature = "di")]
69 state.serialize_field("raw_body", &self.raw_body.as_ref().map(AsRef::as_ref))?;
70 #[cfg(not(feature = "di"))]
71 state.serialize_field("raw_body", &self.raw_body)?;
72 state.serialize_field("headers", &*self.headers)?;
73 state.serialize_field("cookies", &*self.cookies)?;
74 state.serialize_field("method", &self.method)?;
75 state.serialize_field("path", &self.path)?;
76 state.end()
77 }
78}
79
80impl<'de> Deserialize<'de> for RequestData {
81 #[allow(clippy::too_many_lines)]
82 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
83 where
84 D: serde::Deserializer<'de>,
85 {
86 #[derive(Deserialize)]
87 #[serde(field_identifier, rename_all = "snake_case")]
88 enum Field {
89 PathParams,
90 QueryParams,
91 ValidatedParams,
92 RawQueryParams,
93 Body,
94 RawBody,
95 Headers,
96 Cookies,
97 Method,
98 Path,
99 }
100
101 struct RequestDataVisitor;
102
103 impl<'de> serde::de::Visitor<'de> for RequestDataVisitor {
104 type Value = RequestData;
105
106 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
107 formatter.write_str("struct RequestData")
108 }
109
110 fn visit_map<V>(self, mut map: V) -> Result<RequestData, V::Error>
111 where
112 V: serde::de::MapAccess<'de>,
113 {
114 let mut path_params = None;
115 let mut query_params = None;
116 let mut validated_params = None;
117 let mut raw_query_params = None;
118 let mut body = None;
119 let mut raw_body = None;
120 let mut headers = None;
121 let mut cookies = None;
122 let mut method = None;
123 let mut path = None;
124
125 while let Some(key) = map.next_key()? {
126 match key {
127 Field::PathParams => {
128 path_params = Some(Arc::new(map.next_value()?));
129 }
130 Field::QueryParams => {
131 query_params = Some(map.next_value()?);
132 }
133 Field::ValidatedParams => {
134 validated_params = Some(map.next_value()?);
135 }
136 Field::RawQueryParams => {
137 raw_query_params = Some(Arc::new(map.next_value()?));
138 }
139 Field::Body => {
140 body = Some(map.next_value()?);
141 }
142 Field::RawBody => {
143 let bytes_vec: Option<Vec<u8>> = map.next_value()?;
144 #[cfg(feature = "di")]
145 {
146 raw_body = bytes_vec.map(Bytes::from);
147 }
148 #[cfg(not(feature = "di"))]
149 {
150 raw_body = bytes_vec;
151 }
152 }
153 Field::Headers => {
154 headers = Some(Arc::new(map.next_value()?));
155 }
156 Field::Cookies => {
157 cookies = Some(Arc::new(map.next_value()?));
158 }
159 Field::Method => {
160 method = Some(map.next_value()?);
161 }
162 Field::Path => {
163 path = Some(map.next_value()?);
164 }
165 }
166 }
167
168 Ok(RequestData {
169 path_params: path_params.ok_or_else(|| serde::de::Error::missing_field("path_params"))?,
170 query_params: query_params.ok_or_else(|| serde::de::Error::missing_field("query_params"))?,
171 validated_params,
172 raw_query_params: raw_query_params
173 .ok_or_else(|| serde::de::Error::missing_field("raw_query_params"))?,
174 body: body.ok_or_else(|| serde::de::Error::missing_field("body"))?,
175 raw_body,
176 headers: headers.ok_or_else(|| serde::de::Error::missing_field("headers"))?,
177 cookies: cookies.ok_or_else(|| serde::de::Error::missing_field("cookies"))?,
178 method: method.ok_or_else(|| serde::de::Error::missing_field("method"))?,
179 path: path.ok_or_else(|| serde::de::Error::missing_field("path"))?,
180 #[cfg(feature = "di")]
181 dependencies: None,
182 })
183 }
184 }
185
186 const FIELDS: &[&str] = &[
187 "path_params",
188 "query_params",
189 "validated_params",
190 "raw_query_params",
191 "body",
192 "raw_body",
193 "headers",
194 "cookies",
195 "method",
196 "path",
197 ];
198 deserializer.deserialize_struct("RequestData", FIELDS, RequestDataVisitor)
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use serde_json::{Value, json};
206
207 #[derive(Default)]
208 struct RequestDataCollections {
209 raw_query_params: HashMap<String, Vec<String>>,
210 headers: HashMap<String, String>,
211 cookies: HashMap<String, String>,
212 path_params: HashMap<String, String>,
213 }
214
215 fn create_request_data(
216 path: &str,
217 method: &str,
218 body: Value,
219 query_params: Value,
220 collections: RequestDataCollections,
221 ) -> RequestData {
222 RequestData {
223 path_params: Arc::new(collections.path_params),
224 query_params,
225 validated_params: None,
226 raw_query_params: Arc::new(collections.raw_query_params),
227 body,
228 raw_body: None,
229 headers: Arc::new(collections.headers),
230 cookies: Arc::new(collections.cookies),
231 method: method.to_string(),
232 path: path.to_string(),
233 #[cfg(feature = "di")]
234 dependencies: None,
235 }
236 }
237
238 #[test]
239 fn test_request_data_minimal() {
240 let data = create_request_data(
241 "/api/users",
242 "GET",
243 json!(null),
244 json!({}),
245 RequestDataCollections::default(),
246 );
247
248 assert_eq!(data.path, "/api/users");
249 assert_eq!(data.method, "GET");
250 assert_eq!(data.body, json!(null));
251 }
252
253 #[test]
254 fn test_request_data_with_json_body() {
255 let body = json!({
256 "name": "test_user",
257 "email": "test@example.com",
258 "age": 30
259 });
260
261 let data = create_request_data(
262 "/api/users",
263 "POST",
264 body.clone(),
265 json!({}),
266 RequestDataCollections::default(),
267 );
268
269 assert_eq!(data.body, body);
270 assert_eq!(data.body["name"], "test_user");
271 assert_eq!(data.body["email"], "test@example.com");
272 assert_eq!(data.body["age"], 30);
273 }
274
275 #[test]
276 fn test_request_data_with_query_params() {
277 let mut raw_query_params = HashMap::new();
278 raw_query_params.insert("page".to_string(), vec!["1".to_string()]);
279 raw_query_params.insert("limit".to_string(), vec!["10".to_string()]);
280 raw_query_params.insert("tags".to_string(), vec!["rust".to_string(), "web".to_string()]);
281
282 let query_params = json!({
283 "page": "1",
284 "limit": "10",
285 "tags": ["rust", "web"]
286 });
287
288 let data = create_request_data(
289 "/api/users",
290 "GET",
291 json!(null),
292 query_params,
293 RequestDataCollections {
294 raw_query_params,
295 ..Default::default()
296 },
297 );
298
299 assert_eq!(data.raw_query_params.get("page"), Some(&vec!["1".to_string()]));
300 assert_eq!(data.raw_query_params.get("limit"), Some(&vec!["10".to_string()]));
301 assert_eq!(
302 data.raw_query_params.get("tags"),
303 Some(&vec!["rust".to_string(), "web".to_string()])
304 );
305 }
306
307 #[test]
308 fn test_request_data_with_headers() {
309 let mut headers = HashMap::new();
310 headers.insert("content-type".to_string(), "application/json".to_string());
311 headers.insert("authorization".to_string(), "Bearer token123".to_string());
312 headers.insert("user-agent".to_string(), "Mozilla/5.0".to_string());
313
314 let data = create_request_data(
315 "/api/users",
316 "GET",
317 json!(null),
318 json!({}),
319 RequestDataCollections {
320 headers,
321 ..Default::default()
322 },
323 );
324
325 assert_eq!(data.headers.get("content-type"), Some(&"application/json".to_string()));
326 assert_eq!(data.headers.get("authorization"), Some(&"Bearer token123".to_string()));
327 assert_eq!(data.headers.get("user-agent"), Some(&"Mozilla/5.0".to_string()));
328 }
329
330 #[test]
331 fn test_request_data_with_cookies() {
332 let mut cookies = HashMap::new();
333 cookies.insert("session_id".to_string(), "abc123xyz".to_string());
334 cookies.insert("user_id".to_string(), "user_42".to_string());
335 cookies.insert("theme".to_string(), "dark".to_string());
336
337 let data = create_request_data(
338 "/api/users",
339 "GET",
340 json!(null),
341 json!({}),
342 RequestDataCollections {
343 cookies,
344 ..Default::default()
345 },
346 );
347
348 assert_eq!(data.cookies.get("session_id"), Some(&"abc123xyz".to_string()));
349 assert_eq!(data.cookies.get("user_id"), Some(&"user_42".to_string()));
350 assert_eq!(data.cookies.get("theme"), Some(&"dark".to_string()));
351 }
352
353 #[test]
354 fn test_request_data_with_path_params() {
355 let mut path_params = HashMap::new();
356 path_params.insert("user_id".to_string(), "123".to_string());
357 path_params.insert("post_id".to_string(), "456".to_string());
358
359 let data = create_request_data(
360 "/api/users/123/posts/456",
361 "GET",
362 json!(null),
363 json!({}),
364 RequestDataCollections {
365 path_params,
366 ..Default::default()
367 },
368 );
369
370 assert_eq!(data.path_params.get("user_id"), Some(&"123".to_string()));
371 assert_eq!(data.path_params.get("post_id"), Some(&"456".to_string()));
372 }
373
374 #[test]
375 fn test_request_data_all_fields_populated() {
376 let mut path_params = HashMap::new();
377 path_params.insert("id".to_string(), "user_99".to_string());
378
379 let mut raw_query_params = HashMap::new();
380 raw_query_params.insert("filter".to_string(), vec!["active".to_string()]);
381
382 let mut headers = HashMap::new();
383 headers.insert("content-type".to_string(), "application/json".to_string());
384
385 let mut cookies = HashMap::new();
386 cookies.insert("session".to_string(), "xyz789".to_string());
387
388 let body = json!({
389 "name": "John",
390 "email": "john@example.com"
391 });
392
393 let query_params = json!({
394 "filter": "active"
395 });
396
397 let data = create_request_data(
398 "/api/users/user_99",
399 "PUT",
400 body,
401 query_params,
402 RequestDataCollections {
403 raw_query_params,
404 headers,
405 cookies,
406 path_params,
407 },
408 );
409
410 assert_eq!(data.path, "/api/users/user_99");
411 assert_eq!(data.method, "PUT");
412 assert_eq!(data.path_params.get("id"), Some(&"user_99".to_string()));
413 assert_eq!(data.body["name"], "John");
414 assert_eq!(data.headers.get("content-type"), Some(&"application/json".to_string()));
415 assert_eq!(data.cookies.get("session"), Some(&"xyz789".to_string()));
416 }
417
418 #[test]
419 fn test_request_data_empty_collections() {
420 let data = create_request_data(
421 "/api/test",
422 "GET",
423 json!(null),
424 json!({}),
425 RequestDataCollections::default(),
426 );
427
428 assert!(data.path_params.is_empty());
429 assert!(data.raw_query_params.is_empty());
430 assert!(data.headers.is_empty());
431 assert!(data.cookies.is_empty());
432 }
433
434 #[test]
435 fn test_request_data_clone() {
436 let mut path_params = HashMap::new();
437 path_params.insert("id".to_string(), "123".to_string());
438
439 let data1 = create_request_data(
440 "/api/users/123",
441 "GET",
442 json!({"name": "test"}),
443 json!({}),
444 RequestDataCollections {
445 path_params,
446 ..Default::default()
447 },
448 );
449
450 let data2 = data1.clone();
451
452 assert_eq!(data1.path, data2.path);
453 assert_eq!(data1.method, data2.method);
454 assert_eq!(data1.body, data2.body);
455 assert_eq!(data1.path_params, data2.path_params);
456 }
457
458 #[test]
459 fn test_request_data_various_http_methods() {
460 let methods = vec!["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
461
462 for method in methods {
463 let data = create_request_data(
464 "/api/test",
465 method,
466 json!(null),
467 json!({}),
468 RequestDataCollections::default(),
469 );
470
471 assert_eq!(data.method, method);
472 }
473 }
474
475 #[test]
476 fn test_request_data_raw_body_none() {
477 let data = create_request_data(
478 "/api/test",
479 "GET",
480 json!(null),
481 json!({}),
482 RequestDataCollections::default(),
483 );
484
485 assert!(data.raw_body.is_none());
486 }
487
488 #[cfg(not(feature = "di"))]
489 #[test]
490 fn test_request_data_raw_body_some() {
491 let raw_body_bytes = vec![1, 2, 3, 4, 5];
492 let mut data = create_request_data(
493 "/api/test",
494 "POST",
495 json!(null),
496 json!({}),
497 RequestDataCollections::default(),
498 );
499
500 data.raw_body = Some(raw_body_bytes.clone());
501 assert_eq!(data.raw_body, Some(raw_body_bytes));
502 }
503
504 #[cfg(not(feature = "di"))]
505 #[test]
506 fn request_data_serializes_and_deserializes() {
507 let mut headers = HashMap::new();
508 headers.insert("content-type".to_string(), "application/json".to_string());
509
510 let mut cookies = HashMap::new();
511 cookies.insert("session".to_string(), "abc".to_string());
512
513 let mut raw_query_params = HashMap::new();
514 raw_query_params.insert("tags".to_string(), vec!["rust".to_string(), "http".to_string()]);
515
516 let mut path_params = HashMap::new();
517 path_params.insert("id".to_string(), "123".to_string());
518
519 let mut data = create_request_data(
520 "/api/items/123",
521 "POST",
522 json!({"name": "demo"}),
523 json!({"tags": ["rust", "http"]}),
524 RequestDataCollections {
525 raw_query_params,
526 headers,
527 cookies,
528 path_params,
529 },
530 );
531 data.raw_body = Some(vec![9, 8, 7]);
532
533 let encoded = serde_json::to_string(&data).expect("serialize RequestData");
534 let decoded: RequestData = serde_json::from_str(&encoded).expect("deserialize RequestData");
535
536 assert_eq!(decoded.path, "/api/items/123");
537 assert_eq!(decoded.method, "POST");
538 assert_eq!(decoded.body["name"], "demo");
539 assert_eq!(decoded.query_params["tags"][0], "rust");
540 assert_eq!(
541 decoded.raw_query_params.get("tags").unwrap(),
542 &vec!["rust".to_string(), "http".to_string()]
543 );
544 assert_eq!(decoded.headers.get("content-type").unwrap(), "application/json");
545 assert_eq!(decoded.cookies.get("session").unwrap(), "abc");
546 assert_eq!(decoded.path_params.get("id").unwrap(), "123");
547 assert_eq!(decoded.raw_body, Some(vec![9, 8, 7]));
548 }
549
550 #[test]
551 fn test_request_data_multiple_query_param_values() {
552 let mut raw_query_params = HashMap::new();
553 raw_query_params.insert(
554 "colors".to_string(),
555 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
556 );
557
558 let data = create_request_data(
559 "/api/items",
560 "GET",
561 json!(null),
562 json!({}),
563 RequestDataCollections {
564 raw_query_params,
565 ..Default::default()
566 },
567 );
568
569 let colors = data.raw_query_params.get("colors").unwrap();
570 assert_eq!(colors.len(), 3);
571 assert!(colors.contains(&"red".to_string()));
572 assert!(colors.contains(&"green".to_string()));
573 assert!(colors.contains(&"blue".to_string()));
574 }
575
576 #[test]
577 fn test_request_data_complex_json_body() {
578 let body = json!({
579 "user": {
580 "name": "Alice",
581 "profile": {
582 "age": 28,
583 "location": "San Francisco"
584 }
585 },
586 "tags": ["admin", "active"],
587 "metadata": {
588 "created_at": "2024-01-01",
589 "updated_at": "2024-12-01"
590 }
591 });
592
593 let data = create_request_data("/api/users", "POST", body, json!({}), RequestDataCollections::default());
594
595 assert_eq!(data.body["user"]["name"], "Alice");
596 assert_eq!(data.body["user"]["profile"]["age"], 28);
597 assert_eq!(data.body["tags"][0], "admin");
598 assert_eq!(data.body["metadata"]["created_at"], "2024-01-01");
599 }
600
601 #[test]
602 fn test_request_data_special_characters_in_paths() {
603 let data = create_request_data(
604 "/api/users/john@example.com/posts",
605 "GET",
606 json!(null),
607 json!({}),
608 RequestDataCollections::default(),
609 );
610
611 assert_eq!(data.path, "/api/users/john@example.com/posts");
612 }
613
614 #[test]
615 fn test_request_data_special_characters_in_params() {
616 let mut path_params = HashMap::new();
617 path_params.insert("email".to_string(), "test@example.com".to_string());
618 path_params.insert("slug".to_string(), "my-post-title".to_string());
619
620 let data = create_request_data(
621 "/api/users/test@example.com",
622 "GET",
623 json!(null),
624 json!({}),
625 RequestDataCollections {
626 path_params,
627 ..Default::default()
628 },
629 );
630
631 assert_eq!(data.path_params.get("email"), Some(&"test@example.com".to_string()));
632 assert_eq!(data.path_params.get("slug"), Some(&"my-post-title".to_string()));
633 }
634
635 #[test]
636 fn test_request_data_null_and_empty_values() {
637 let body = json!({
638 "name": null,
639 "email": "",
640 "age": 0,
641 "active": false
642 });
643
644 let data = create_request_data("/api/users", "POST", body, json!({}), RequestDataCollections::default());
645
646 assert!(data.body["name"].is_null());
647 assert_eq!(data.body["email"], "");
648 assert_eq!(data.body["age"], 0);
649 assert_eq!(data.body["active"], false);
650 }
651
652 #[test]
653 fn test_request_data_serialization() {
654 let mut path_params = HashMap::new();
655 path_params.insert("id".to_string(), "123".to_string());
656
657 let mut headers = HashMap::new();
658 headers.insert("content-type".to_string(), "application/json".to_string());
659
660 let data = create_request_data(
661 "/api/users/123",
662 "GET",
663 json!({"name": "test"}),
664 json!({"page": "1"}),
665 RequestDataCollections {
666 headers,
667 path_params,
668 ..Default::default()
669 },
670 );
671
672 let serialized = serde_json::to_string(&data);
673 assert!(serialized.is_ok());
674 }
675
676 #[test]
677 fn test_request_data_delete_request() {
678 let mut path_params = HashMap::new();
679 path_params.insert("id".to_string(), "999".to_string());
680
681 let data = create_request_data(
682 "/api/users/999",
683 "DELETE",
684 json!(null),
685 json!({}),
686 RequestDataCollections {
687 path_params,
688 ..Default::default()
689 },
690 );
691
692 assert_eq!(data.method, "DELETE");
693 assert_eq!(data.path_params.get("id"), Some(&"999".to_string()));
694 }
695
696 #[test]
697 fn test_request_data_array_body() {
698 let body = json!([
699 {"id": 1, "name": "item1"},
700 {"id": 2, "name": "item2"},
701 {"id": 3, "name": "item3"}
702 ]);
703
704 let data = create_request_data("/api/items", "POST", body, json!({}), RequestDataCollections::default());
705
706 assert!(data.body.is_array());
707 assert_eq!(data.body.as_array().unwrap().len(), 3);
708 assert_eq!(data.body[0]["id"], 1);
709 assert_eq!(data.body[2]["name"], "item3");
710 }
711
712 #[test]
713 fn test_request_data_case_sensitive_keys() {
714 let mut headers = HashMap::new();
715 headers.insert("Content-Type".to_string(), "application/json".to_string());
716 headers.insert("content-type".to_string(), "text/plain".to_string());
717
718 let data = create_request_data(
719 "/api/test",
720 "GET",
721 json!(null),
722 json!({}),
723 RequestDataCollections {
724 headers,
725 ..Default::default()
726 },
727 );
728
729 assert_eq!(data.headers.get("Content-Type"), Some(&"application/json".to_string()));
730 assert_eq!(data.headers.get("content-type"), Some(&"text/plain".to_string()));
731 }
732
733 #[test]
734 fn test_request_data_serialization_with_all_fields() {
735 let mut path_params = HashMap::new();
736 path_params.insert("id".to_string(), "42".to_string());
737
738 let mut raw_query_params = HashMap::new();
739 raw_query_params.insert("page".to_string(), vec!["2".to_string()]);
740
741 let mut headers = HashMap::new();
742 headers.insert("authorization".to_string(), "Bearer xyz".to_string());
743
744 let mut cookies = HashMap::new();
745 cookies.insert("token".to_string(), "abc123".to_string());
746
747 let data = create_request_data(
748 "/api/resource/42",
749 "PUT",
750 json!({"status": "updated"}),
751 json!({"page": "2"}),
752 RequestDataCollections {
753 raw_query_params,
754 headers,
755 cookies,
756 path_params,
757 },
758 );
759
760 let serialized = serde_json::to_string(&data).expect("serialization failed");
761 assert!(!serialized.is_empty());
762 assert!(serialized.contains("\"id\":\"42\""));
763 assert!(serialized.contains("PUT"));
764 }
765
766 #[test]
767 fn test_request_data_deserialization() {
768 let json_str = r#"{
769 "path_params": {"user_id": "123"},
770 "query_params": {"page": "1"},
771 "raw_query_params": {"page": ["1"]},
772 "body": {"name": "test"},
773 "raw_body": null,
774 "headers": {"content-type": "application/json"},
775 "cookies": {"session": "abc"},
776 "method": "POST",
777 "path": "/api/users"
778 }"#;
779
780 let deserialized: RequestData = serde_json::from_str(json_str).expect("deserialization failed");
781
782 assert_eq!(deserialized.method, "POST");
783 assert_eq!(deserialized.path, "/api/users");
784 assert_eq!(deserialized.path_params.get("user_id"), Some(&"123".to_string()));
785 assert_eq!(deserialized.body["name"], "test");
786 assert_eq!(
787 deserialized.headers.get("content-type"),
788 Some(&"application/json".to_string())
789 );
790 assert_eq!(deserialized.cookies.get("session"), Some(&"abc".to_string()));
791 }
792
793 #[test]
794 fn test_request_data_roundtrip_serialization() {
795 let mut path_params = HashMap::new();
796 path_params.insert("item_id".to_string(), "789".to_string());
797
798 let mut raw_query_params = HashMap::new();
799 raw_query_params.insert("sort".to_string(), vec!["desc".to_string()]);
800
801 let mut headers = HashMap::new();
802 headers.insert("x-custom-header".to_string(), "value123".to_string());
803
804 let mut cookies = HashMap::new();
805 cookies.insert("prefer".to_string(), "dark_mode".to_string());
806
807 let original = create_request_data(
808 "/api/items/789",
809 "DELETE",
810 json!({"reason": "archived"}),
811 json!({"sort": "desc"}),
812 RequestDataCollections {
813 raw_query_params,
814 headers,
815 cookies,
816 path_params,
817 },
818 );
819
820 let serialized = serde_json::to_string(&original).expect("serialization failed");
821 let deserialized: RequestData = serde_json::from_str(&serialized).expect("deserialization failed");
822
823 assert_eq!(deserialized.method, original.method);
824 assert_eq!(deserialized.path, original.path);
825 assert_eq!(deserialized.body, original.body);
826 assert_eq!(deserialized.path_params, original.path_params);
827 }
828
829 #[test]
830 fn test_request_data_large_json_body() {
831 let mut large_obj = serde_json::Map::new();
832 for i in 0..100 {
833 large_obj.insert(format!("field_{i}"), json!({"value": i, "name": format!("item_{}", i)}));
834 }
835 let body = json!(large_obj);
836
837 let data = create_request_data("/api/batch", "POST", body, json!({}), RequestDataCollections::default());
838
839 assert!(data.body.is_object());
840 assert_eq!(data.body.as_object().unwrap().len(), 100);
841 }
842
843 #[test]
844 fn test_request_data_deeply_nested_json() {
845 let body = json!({
846 "level1": {
847 "level2": {
848 "level3": {
849 "level4": {
850 "level5": {
851 "value": "deep"
852 }
853 }
854 }
855 }
856 }
857 });
858
859 let data = create_request_data("/api/nested", "GET", body, json!({}), RequestDataCollections::default());
860
861 assert_eq!(
862 data.body["level1"]["level2"]["level3"]["level4"]["level5"]["value"],
863 "deep"
864 );
865 }
866
867 #[test]
868 fn test_request_data_unicode_in_fields() {
869 let mut path_params = HashMap::new();
870 path_params.insert("name".to_string(), "用户".to_string());
871
872 let mut cookies = HashMap::new();
873 cookies.insert("msg".to_string(), "こんにちは".to_string());
874
875 let body = json!({
876 "greeting": "مرحبا",
877 "emoji": "🚀"
878 });
879
880 let data = create_request_data(
881 "/api/users/用户",
882 "POST",
883 body,
884 json!({}),
885 RequestDataCollections {
886 cookies,
887 path_params,
888 ..Default::default()
889 },
890 );
891
892 assert_eq!(data.path_params.get("name"), Some(&"用户".to_string()));
893 assert_eq!(data.cookies.get("msg"), Some(&"こんにちは".to_string()));
894 assert_eq!(data.body["emoji"], "🚀");
895 }
896
897 #[test]
898 fn test_request_data_multiple_headers_with_same_prefix() {
899 let mut headers = HashMap::new();
900 headers.insert("x-custom-1".to_string(), "value1".to_string());
901 headers.insert("x-custom-2".to_string(), "value2".to_string());
902 headers.insert("x-custom-3".to_string(), "value3".to_string());
903
904 let data = create_request_data(
905 "/api/test",
906 "GET",
907 json!(null),
908 json!({}),
909 RequestDataCollections {
910 headers,
911 ..Default::default()
912 },
913 );
914
915 assert_eq!(data.headers.get("x-custom-1"), Some(&"value1".to_string()));
916 assert_eq!(data.headers.get("x-custom-2"), Some(&"value2".to_string()));
917 assert_eq!(data.headers.get("x-custom-3"), Some(&"value3".to_string()));
918 assert_eq!(data.headers.len(), 3);
919 }
920
921 #[test]
922 fn test_request_data_numeric_values_in_json() {
923 let body = json!({
924 "int": 42,
925 "float": 3.2,
926 "negative": -100,
927 "zero": 0,
928 "large": 9_223_372_036_854_775_807i64
929 });
930
931 let data = create_request_data(
932 "/api/numbers",
933 "POST",
934 body,
935 json!({}),
936 RequestDataCollections::default(),
937 );
938
939 assert_eq!(data.body["int"], 42);
940 assert_eq!(data.body["float"], 3.2);
941 assert_eq!(data.body["negative"], -100);
942 assert_eq!(data.body["zero"], 0);
943 }
944
945 #[test]
946 fn test_request_data_boolean_values_in_json() {
947 let body = json!({
948 "is_active": true,
949 "is_admin": false
950 });
951
952 let data = create_request_data("/api/config", "GET", body, json!({}), RequestDataCollections::default());
953
954 assert_eq!(data.body["is_active"], true);
955 assert_eq!(data.body["is_admin"], false);
956 }
957
958 #[test]
959 fn test_request_data_missing_optional_raw_body() {
960 let data = create_request_data(
961 "/api/test",
962 "GET",
963 json!(null),
964 json!({}),
965 RequestDataCollections::default(),
966 );
967
968 assert!(data.raw_body.is_none());
969 }
970
971 #[test]
972 fn test_request_data_path_with_query_string_format() {
973 let data = create_request_data(
974 "/api/search?q=test&limit=10",
975 "GET",
976 json!(null),
977 json!({"q": "test", "limit": "10"}),
978 RequestDataCollections::default(),
979 );
980
981 assert_eq!(data.path, "/api/search?q=test&limit=10");
982 }
983
984 #[test]
985 fn test_request_data_root_path() {
986 let data = create_request_data("/", "GET", json!(null), json!({}), RequestDataCollections::default());
987
988 assert_eq!(data.path, "/");
989 }
990
991 #[test]
992 fn test_request_data_empty_string_values() {
993 let mut headers = HashMap::new();
994 headers.insert("empty-header".to_string(), String::new());
995
996 let mut path_params = HashMap::new();
997 path_params.insert("id".to_string(), String::new());
998
999 let data = create_request_data(
1000 "/api/test",
1001 "GET",
1002 json!(null),
1003 json!({}),
1004 RequestDataCollections {
1005 headers,
1006 path_params,
1007 ..Default::default()
1008 },
1009 );
1010
1011 assert_eq!(data.headers.get("empty-header"), Some(&String::new()));
1012 assert_eq!(data.path_params.get("id"), Some(&String::new()));
1013 }
1014
1015 #[test]
1016 fn test_request_data_deserialization_missing_field() {
1017 let json_str = r#"{
1018 "path_params": {"user_id": "123"},
1019 "query_params": {"page": "1"},
1020 "raw_query_params": {"page": ["1"]},
1021 "body": {"name": "test"},
1022 "raw_body": null,
1023 "headers": {"content-type": "application/json"},
1024 "cookies": {"session": "abc"}
1025 }"#;
1026
1027 let result: Result<RequestData, _> = serde_json::from_str(json_str);
1028 assert!(result.is_err());
1029 }
1030
1031 #[test]
1032 fn test_request_data_deserialization_extra_fields_rejected() {
1033 let json_str = r#"{
1034 "path_params": {"user_id": "123"},
1035 "query_params": {"page": "1"},
1036 "raw_query_params": {"page": ["1"]},
1037 "body": {"name": "test"},
1038 "raw_body": null,
1039 "headers": {"content-type": "application/json"},
1040 "cookies": {"session": "abc"},
1041 "method": "GET",
1042 "path": "/api/test",
1043 "extra_field": "not allowed"
1044 }"#;
1045
1046 let result: Result<RequestData, _> = serde_json::from_str(json_str);
1047 assert!(result.is_err());
1048 }
1049
1050 #[test]
1051 fn test_request_data_multiple_raw_body_values() {
1052 let mut raw_query_params = HashMap::new();
1053 raw_query_params.insert(
1054 "data".to_string(),
1055 vec!["val1".to_string(), "val2".to_string(), "val3".to_string()],
1056 );
1057
1058 let data = create_request_data(
1059 "/api/test",
1060 "POST",
1061 json!(null),
1062 json!({}),
1063 RequestDataCollections {
1064 raw_query_params,
1065 ..Default::default()
1066 },
1067 );
1068
1069 let values = data.raw_query_params.get("data").unwrap();
1070 assert_eq!(values.len(), 3);
1071 assert_eq!(values[0], "val1");
1072 assert_eq!(values[1], "val2");
1073 assert_eq!(values[2], "val3");
1074 }
1075
1076 #[test]
1077 fn test_request_data_debug_output() {
1078 let data = create_request_data(
1079 "/api/test",
1080 "GET",
1081 json!({"key": "value"}),
1082 json!({}),
1083 RequestDataCollections::default(),
1084 );
1085
1086 let debug_str = format!("{data:?}");
1087 assert!(debug_str.contains("RequestData"));
1088 assert!(debug_str.contains("/api/test"));
1089 }
1090
1091 #[test]
1092 fn test_request_data_clone_independence() {
1093 let mut path_params1 = HashMap::new();
1094 path_params1.insert("id".to_string(), "original".to_string());
1095
1096 let data1 = create_request_data(
1097 "/api/users/1",
1098 "GET",
1099 json!({"name": "original"}),
1100 json!({}),
1101 RequestDataCollections {
1102 path_params: path_params1,
1103 ..Default::default()
1104 },
1105 );
1106
1107 let data2 = data1.clone();
1108
1109 assert_eq!(data1.path_params.get("id"), data2.path_params.get("id"));
1110 assert_eq!(data1.body["name"], data2.body["name"]);
1111 }
1112
1113 #[test]
1114 fn deserialize_errors_on_missing_required_field() {
1115 let value = json!({
1116 "path_params": {},
1117 "query_params": {},
1118 "raw_query_params": {},
1119 "body": null,
1120 "raw_body": null,
1121 "headers": {},
1122 "cookies": {},
1123 "method": "GET"
1124 });
1125
1126 let err = serde_json::from_value::<RequestData>(value).unwrap_err();
1127 assert!(err.to_string().contains("missing field"));
1128 }
1129
1130 #[test]
1131 fn deserialize_errors_on_invalid_raw_body_type() {
1132 let value = json!({
1133 "path_params": {},
1134 "query_params": {},
1135 "raw_query_params": {},
1136 "body": null,
1137 "raw_body": "not-bytes",
1138 "headers": {},
1139 "cookies": {},
1140 "method": "GET",
1141 "path": "/"
1142 });
1143
1144 assert!(serde_json::from_value::<RequestData>(value).is_err());
1145 }
1146}