1use axum::{
7 body::Body,
8 http::{Request, Response, StatusCode},
9};
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use std::collections::HashMap;
13use std::future::Future;
14use std::pin::Pin;
15
16#[derive(Debug, Clone)]
26pub struct RequestData {
27 pub path_params: std::sync::Arc<HashMap<String, String>>,
28 pub query_params: std::sync::Arc<Value>,
29 pub validated_params: Option<std::sync::Arc<Value>>,
31 pub raw_query_params: std::sync::Arc<HashMap<String, Vec<String>>>,
32 pub body: std::sync::Arc<Value>,
33 pub raw_body: Option<bytes::Bytes>,
34 pub headers: std::sync::Arc<HashMap<String, String>>,
35 pub cookies: std::sync::Arc<HashMap<String, String>>,
36 pub method: String,
37 pub path: String,
38 #[cfg(feature = "di")]
40 pub dependencies: Option<std::sync::Arc<spikard_core::di::ResolvedDependencies>>,
41}
42
43impl Serialize for RequestData {
44 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
45 where
46 S: serde::Serializer,
47 {
48 use serde::ser::SerializeStruct;
49 #[cfg(feature = "di")]
50 let field_count = 11;
51 #[cfg(not(feature = "di"))]
52 let field_count = 10;
53
54 let mut state = serializer.serialize_struct("RequestData", field_count)?;
55 state.serialize_field("path_params", &*self.path_params)?;
56 state.serialize_field("query_params", &*self.query_params)?;
57 state.serialize_field("validated_params", &self.validated_params.as_deref())?;
58 state.serialize_field("raw_query_params", &*self.raw_query_params)?;
59 state.serialize_field("body", &*self.body)?;
60 state.serialize_field("raw_body", &self.raw_body.as_ref().map(|b| b.as_ref()))?;
61 state.serialize_field("headers", &*self.headers)?;
62 state.serialize_field("cookies", &*self.cookies)?;
63 state.serialize_field("method", &self.method)?;
64 state.serialize_field("path", &self.path)?;
65
66 #[cfg(feature = "di")]
67 {
68 state.serialize_field("has_dependencies", &self.dependencies.is_some())?;
69 }
70
71 state.end()
72 }
73}
74
75impl<'de> Deserialize<'de> for RequestData {
76 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77 where
78 D: serde::Deserializer<'de>,
79 {
80 #[derive(Deserialize)]
81 #[serde(field_identifier, rename_all = "snake_case")]
82 enum Field {
83 PathParams,
84 QueryParams,
85 RawQueryParams,
86 ValidatedParams,
87 Body,
88 RawBody,
89 Headers,
90 Cookies,
91 Method,
92 Path,
93 #[cfg(feature = "di")]
94 HasDependencies,
95 }
96
97 struct RequestDataVisitor;
98
99 impl<'de> serde::de::Visitor<'de> for RequestDataVisitor {
100 type Value = RequestData;
101
102 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
103 formatter.write_str("struct RequestData")
104 }
105
106 fn visit_map<V>(self, mut map: V) -> Result<RequestData, V::Error>
107 where
108 V: serde::de::MapAccess<'de>,
109 {
110 let mut path_params = None;
111 let mut query_params = None;
112 let mut raw_query_params = None;
113 let mut validated_params = None;
114 let mut body = None;
115 let mut raw_body = None;
116 let mut headers = None;
117 let mut cookies = None;
118 let mut method = None;
119 let mut path = None;
120
121 while let Some(key) = map.next_key()? {
122 match key {
123 Field::PathParams => {
124 path_params = Some(std::sync::Arc::new(map.next_value()?));
125 }
126 Field::QueryParams => {
127 query_params = Some(std::sync::Arc::new(map.next_value()?));
128 }
129 Field::RawQueryParams => {
130 raw_query_params = Some(std::sync::Arc::new(map.next_value()?));
131 }
132 Field::ValidatedParams => {
133 validated_params = Some(std::sync::Arc::new(map.next_value()?));
134 }
135 Field::Body => {
136 body = Some(std::sync::Arc::new(map.next_value()?));
137 }
138 Field::RawBody => {
139 let bytes_vec: Option<Vec<u8>> = map.next_value()?;
140 raw_body = bytes_vec.map(bytes::Bytes::from);
141 }
142 Field::Headers => {
143 headers = Some(std::sync::Arc::new(map.next_value()?));
144 }
145 Field::Cookies => {
146 cookies = Some(std::sync::Arc::new(map.next_value()?));
147 }
148 Field::Method => {
149 method = Some(map.next_value()?);
150 }
151 Field::Path => {
152 path = Some(map.next_value()?);
153 }
154 #[cfg(feature = "di")]
155 Field::HasDependencies => {
156 let _: bool = map.next_value()?;
157 }
158 }
159 }
160
161 Ok(RequestData {
162 path_params: path_params.ok_or_else(|| serde::de::Error::missing_field("path_params"))?,
163 query_params: query_params.ok_or_else(|| serde::de::Error::missing_field("query_params"))?,
164 raw_query_params: raw_query_params
165 .ok_or_else(|| serde::de::Error::missing_field("raw_query_params"))?,
166 validated_params,
167 body: body.ok_or_else(|| serde::de::Error::missing_field("body"))?,
168 raw_body,
169 headers: headers.ok_or_else(|| serde::de::Error::missing_field("headers"))?,
170 cookies: cookies.ok_or_else(|| serde::de::Error::missing_field("cookies"))?,
171 method: method.ok_or_else(|| serde::de::Error::missing_field("method"))?,
172 path: path.ok_or_else(|| serde::de::Error::missing_field("path"))?,
173 #[cfg(feature = "di")]
174 dependencies: None,
175 })
176 }
177 }
178
179 #[cfg(feature = "di")]
180 const FIELDS: &[&str] = &[
181 "path_params",
182 "query_params",
183 "validated_params",
184 "raw_query_params",
185 "body",
186 "raw_body",
187 "headers",
188 "cookies",
189 "method",
190 "path",
191 "has_dependencies",
192 ];
193
194 #[cfg(not(feature = "di"))]
195 const FIELDS: &[&str] = &[
196 "path_params",
197 "query_params",
198 "validated_params",
199 "raw_query_params",
200 "body",
201 "raw_body",
202 "headers",
203 "cookies",
204 "method",
205 "path",
206 ];
207
208 deserializer.deserialize_struct("RequestData", FIELDS, RequestDataVisitor)
209 }
210}
211
212pub type HandlerResult = Result<Response<Body>, (StatusCode, String)>;
214
215pub trait Handler: Send + Sync {
220 fn call(
226 &self,
227 request: Request<Body>,
228 request_data: RequestData,
229 ) -> Pin<Box<dyn Future<Output = HandlerResult> + Send + '_>>;
230
231 fn prefers_raw_json_body(&self) -> bool {
237 false
238 }
239
240 fn prefers_parameter_extraction(&self) -> bool {
247 false
248 }
249
250 fn wants_headers(&self) -> bool {
255 true
256 }
257
258 fn wants_cookies(&self) -> bool {
262 true
263 }
264
265 fn wants_request_extensions(&self) -> bool {
270 false
271 }
272}
273
274#[derive(Debug, Clone)]
276pub struct ValidatedParams {
277 pub params: HashMap<String, Value>,
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 use std::collections::HashMap;
284
285 fn minimal_request_data() -> RequestData {
286 RequestData {
287 path_params: std::sync::Arc::new(HashMap::new()),
288 query_params: std::sync::Arc::new(Value::Object(serde_json::Map::new())),
289 validated_params: None,
290 raw_query_params: std::sync::Arc::new(HashMap::new()),
291 body: std::sync::Arc::new(Value::Null),
292 raw_body: None,
293 headers: std::sync::Arc::new(HashMap::new()),
294 cookies: std::sync::Arc::new(HashMap::new()),
295 method: "GET".to_string(),
296 path: "/".to_string(),
297 #[cfg(feature = "di")]
298 dependencies: None,
299 }
300 }
301
302 #[test]
303 fn test_request_data_serialization_minimal() {
304 let data = minimal_request_data();
305
306 let json = serde_json::to_value(&data).expect("serialization failed");
307
308 assert!(json["path_params"].is_object());
309 assert!(json["query_params"].is_object());
310 assert!(json["raw_query_params"].is_object());
311 assert!(json["body"].is_null());
312 assert!(json["headers"].is_object());
313 assert!(json["cookies"].is_object());
314 assert_eq!(json["method"], "GET");
315 assert_eq!(json["path"], "/");
316 }
317
318 #[test]
319 fn test_request_data_serialization_with_path_params() {
320 let mut path_params = HashMap::new();
321 path_params.insert("id".to_string(), "123".to_string());
322 path_params.insert("username".to_string(), "alice".to_string());
323
324 let data = RequestData {
325 path_params: std::sync::Arc::new(path_params),
326 ..minimal_request_data()
327 };
328
329 let json = serde_json::to_value(&data).expect("serialization failed");
330
331 assert_eq!(json["path_params"]["id"], "123");
332 assert_eq!(json["path_params"]["username"], "alice");
333 }
334
335 #[test]
336 fn test_request_data_serialization_with_query_params() {
337 let query_params = serde_json::json!({
338 "filter": "active",
339 "limit": 10,
340 "sort": "name"
341 });
342
343 let data = RequestData {
344 query_params: std::sync::Arc::new(query_params),
345 ..minimal_request_data()
346 };
347
348 let json = serde_json::to_value(&data).expect("serialization failed");
349
350 assert_eq!(json["query_params"]["filter"], "active");
351 assert_eq!(json["query_params"]["limit"], 10);
352 assert_eq!(json["query_params"]["sort"], "name");
353 }
354
355 #[test]
356 fn test_request_data_serialization_with_raw_query_params() {
357 let mut raw_query_params = HashMap::new();
358 raw_query_params.insert("tags".to_string(), vec!["rust".to_string(), "web".to_string()]);
359 raw_query_params.insert("category".to_string(), vec!["backend".to_string()]);
360
361 let data = RequestData {
362 raw_query_params: std::sync::Arc::new(raw_query_params),
363 ..minimal_request_data()
364 };
365
366 let json = serde_json::to_value(&data).expect("serialization failed");
367
368 assert!(json["raw_query_params"]["tags"].is_array());
369 assert_eq!(json["raw_query_params"]["tags"][0], "rust");
370 assert_eq!(json["raw_query_params"]["tags"][1], "web");
371 }
372
373 #[test]
374 fn test_request_data_serialization_with_headers() {
375 let mut headers = HashMap::new();
376 headers.insert("content-type".to_string(), "application/json".to_string());
377 headers.insert("authorization".to_string(), "Bearer token123".to_string());
378 headers.insert("user-agent".to_string(), "test-client/1.0".to_string());
379
380 let data = RequestData {
381 headers: std::sync::Arc::new(headers),
382 ..minimal_request_data()
383 };
384
385 let json = serde_json::to_value(&data).expect("serialization failed");
386
387 assert_eq!(json["headers"]["content-type"], "application/json");
388 assert_eq!(json["headers"]["authorization"], "Bearer token123");
389 assert_eq!(json["headers"]["user-agent"], "test-client/1.0");
390 }
391
392 #[test]
393 fn test_request_data_serialization_with_cookies() {
394 let mut cookies = HashMap::new();
395 cookies.insert("session_id".to_string(), "abc123def456".to_string());
396 cookies.insert("preferences".to_string(), "dark_mode=true".to_string());
397
398 let data = RequestData {
399 cookies: std::sync::Arc::new(cookies),
400 ..minimal_request_data()
401 };
402
403 let json = serde_json::to_value(&data).expect("serialization failed");
404
405 assert_eq!(json["cookies"]["session_id"], "abc123def456");
406 assert_eq!(json["cookies"]["preferences"], "dark_mode=true");
407 }
408
409 #[test]
410 fn test_request_data_serialization_with_json_body() {
411 let body = serde_json::json!({
412 "name": "test",
413 "age": 30,
414 "active": true,
415 "tags": ["a", "b"]
416 });
417
418 let data = RequestData {
419 body: std::sync::Arc::new(body),
420 ..minimal_request_data()
421 };
422
423 let json = serde_json::to_value(&data).expect("serialization failed");
424
425 assert_eq!(json["body"]["name"], "test");
426 assert_eq!(json["body"]["age"], 30);
427 assert_eq!(json["body"]["active"], true);
428 assert!(json["body"]["tags"].is_array());
429 }
430
431 #[test]
432 fn test_request_data_serialization_with_raw_body() {
433 let raw_body = bytes::Bytes::from("raw body content");
434 let data = RequestData {
435 raw_body: Some(raw_body),
436 ..minimal_request_data()
437 };
438
439 let json = serde_json::to_value(&data).expect("serialization failed");
440
441 assert!(json["raw_body"].is_array());
442 let serialized_bytes: Vec<u8> =
443 serde_json::from_value(json["raw_body"].clone()).expect("failed to deserialize bytes");
444 assert_eq!(serialized_bytes, b"raw body content".to_vec());
445 }
446
447 #[test]
448 fn test_request_data_serialization_with_empty_strings() {
449 let mut headers = HashMap::new();
450 headers.insert("x-empty".to_string(), "".to_string());
451
452 let data = RequestData {
453 method: "".to_string(),
454 path: "".to_string(),
455 headers: std::sync::Arc::new(headers),
456 ..minimal_request_data()
457 };
458
459 let json = serde_json::to_value(&data).expect("serialization failed");
460
461 assert_eq!(json["method"], "");
462 assert_eq!(json["path"], "");
463 assert_eq!(json["headers"]["x-empty"], "");
464 }
465
466 #[test]
467 fn test_request_data_serialization_with_nested_json_body() {
468 let body = serde_json::json!({
469 "user": {
470 "profile": {
471 "name": "Alice",
472 "contact": {
473 "email": "alice@example.com",
474 "phone": null
475 }
476 }
477 },
478 "settings": {
479 "notifications": [true, false, true]
480 }
481 });
482
483 let data = RequestData {
484 body: std::sync::Arc::new(body),
485 ..minimal_request_data()
486 };
487
488 let json = serde_json::to_value(&data).expect("serialization failed");
489
490 assert_eq!(json["body"]["user"]["profile"]["name"], "Alice");
491 assert_eq!(json["body"]["user"]["profile"]["contact"]["email"], "alice@example.com");
492 assert!(json["body"]["user"]["profile"]["contact"]["phone"].is_null());
493 assert_eq!(json["body"]["settings"]["notifications"][0], true);
494 }
495
496 #[test]
497 fn test_request_data_serialization_all_fields_complete() {
498 let mut path_params = HashMap::new();
499 path_params.insert("id".to_string(), "42".to_string());
500
501 let mut raw_query_params = HashMap::new();
502 raw_query_params.insert("filter".to_string(), vec!["active".to_string()]);
503
504 let mut headers = HashMap::new();
505 headers.insert("content-type".to_string(), "application/json".to_string());
506
507 let mut cookies = HashMap::new();
508 cookies.insert("session".to_string(), "xyz789".to_string());
509
510 let body = serde_json::json!({"action": "create"});
511 let raw_body = bytes::Bytes::from("body bytes");
512
513 let data = RequestData {
514 path_params: std::sync::Arc::new(path_params),
515 query_params: std::sync::Arc::new(serde_json::json!({"page": 1})),
516 validated_params: None,
517 raw_query_params: std::sync::Arc::new(raw_query_params),
518 body: std::sync::Arc::new(body),
519 raw_body: Some(raw_body),
520 headers: std::sync::Arc::new(headers),
521 cookies: std::sync::Arc::new(cookies),
522 method: "POST".to_string(),
523 path: "/api/users".to_string(),
524 #[cfg(feature = "di")]
525 dependencies: None,
526 };
527
528 let json = serde_json::to_value(&data).expect("serialization failed");
529
530 assert_eq!(json["path_params"]["id"], "42");
531 assert_eq!(json["query_params"]["page"], 1);
532 assert_eq!(json["raw_query_params"]["filter"][0], "active");
533 assert_eq!(json["body"]["action"], "create");
534 assert!(json["raw_body"].is_array());
535 assert_eq!(json["headers"]["content-type"], "application/json");
536 assert_eq!(json["cookies"]["session"], "xyz789");
537 assert_eq!(json["method"], "POST");
538 assert_eq!(json["path"], "/api/users");
539 }
540
541 #[test]
542 fn test_request_data_clone_shares_arc_data() {
543 let mut path_params = HashMap::new();
544 path_params.insert("id".to_string(), "original".to_string());
545
546 let data1 = RequestData {
547 path_params: std::sync::Arc::new(path_params),
548 ..minimal_request_data()
549 };
550
551 let data2 = data1.clone();
552
553 assert!(std::sync::Arc::ptr_eq(&data1.path_params, &data2.path_params));
554 }
555
556 #[test]
557 fn test_request_data_deserialization_complete() {
558 let json = serde_json::json!({
559 "path_params": {"id": "123"},
560 "query_params": {"filter": "active"},
561 "raw_query_params": {"tags": ["rust", "web"]},
562 "body": {"name": "test"},
563 "raw_body": null,
564 "headers": {"content-type": "application/json"},
565 "cookies": {"session": "abc"},
566 "method": "POST",
567 "path": "/api/test"
568 });
569
570 let data: RequestData = serde_json::from_value(json).expect("deserialization failed");
571
572 assert_eq!(data.path_params.get("id").unwrap(), "123");
573 assert_eq!(data.query_params["filter"], "active");
574 assert_eq!(data.raw_query_params.get("tags").unwrap()[0], "rust");
575 assert_eq!(data.body["name"], "test");
576 assert!(data.raw_body.is_none());
577 assert_eq!(data.headers.get("content-type").unwrap(), "application/json");
578 assert_eq!(data.cookies.get("session").unwrap(), "abc");
579 assert_eq!(data.method, "POST");
580 assert_eq!(data.path, "/api/test");
581 }
582
583 #[test]
584 fn test_request_data_deserialization_with_raw_body_bytes() {
585 let json = serde_json::json!({
586 "path_params": {},
587 "query_params": {},
588 "raw_query_params": {},
589 "body": null,
590 "raw_body": [72, 101, 108, 108, 111],
591 "headers": {},
592 "cookies": {},
593 "method": "GET",
594 "path": "/"
595 });
596
597 let data: RequestData = serde_json::from_value(json).expect("deserialization failed");
598
599 assert!(data.raw_body.is_some());
600 assert_eq!(data.raw_body.unwrap().as_ref(), b"Hello");
601 }
602
603 #[test]
604 fn test_request_data_deserialization_missing_required_field_path_params() {
605 let json = serde_json::json!({
606 "query_params": {},
607 "raw_query_params": {},
608 "body": null,
609 "headers": {},
610 "cookies": {},
611 "method": "GET",
612 "path": "/"
613 });
614
615 let result: Result<RequestData, _> = serde_json::from_value(json);
616 assert!(result.is_err());
617 assert!(result.unwrap_err().to_string().contains("path_params"));
618 }
619
620 #[test]
621 fn test_request_data_deserialization_missing_required_field_method() {
622 let json = serde_json::json!({
623 "path_params": {},
624 "query_params": {},
625 "raw_query_params": {},
626 "body": null,
627 "headers": {},
628 "cookies": {},
629 "path": "/"
630 });
631
632 let result: Result<RequestData, _> = serde_json::from_value(json);
633 assert!(result.is_err());
634 assert!(result.unwrap_err().to_string().contains("method"));
635 }
636
637 #[test]
638 fn test_request_data_serialization_roundtrip() {
639 let original = RequestData {
640 path_params: std::sync::Arc::new({
641 let mut map = HashMap::new();
642 map.insert("id".to_string(), "999".to_string());
643 map
644 }),
645 query_params: std::sync::Arc::new(serde_json::json!({"limit": 50, "offset": 10})),
646 validated_params: None,
647 raw_query_params: std::sync::Arc::new({
648 let mut map = HashMap::new();
649 map.insert("sort".to_string(), vec!["name".to_string(), "date".to_string()]);
650 map
651 }),
652 body: std::sync::Arc::new(serde_json::json!({"title": "New Post", "content": "Hello World"})),
653 raw_body: None,
654 headers: std::sync::Arc::new({
655 let mut map = HashMap::new();
656 map.insert("accept".to_string(), "application/json".to_string());
657 map
658 }),
659 cookies: std::sync::Arc::new({
660 let mut map = HashMap::new();
661 map.insert("user_id".to_string(), "user42".to_string());
662 map
663 }),
664 method: "PUT".to_string(),
665 path: "/blog/posts/999".to_string(),
666 #[cfg(feature = "di")]
667 dependencies: None,
668 };
669
670 let json = serde_json::to_value(&original).expect("serialization failed");
671 let restored: RequestData = serde_json::from_value(json).expect("deserialization failed");
672
673 assert_eq!(*original.path_params, *restored.path_params);
674 assert_eq!(original.query_params, restored.query_params);
675 assert_eq!(*original.raw_query_params, *restored.raw_query_params);
676 assert_eq!(original.body, restored.body);
677 assert_eq!(original.raw_body, restored.raw_body);
678 assert_eq!(*original.headers, *restored.headers);
679 assert_eq!(*original.cookies, *restored.cookies);
680 assert_eq!(original.method, restored.method);
681 assert_eq!(original.path, restored.path);
682 }
683
684 #[test]
685 fn test_request_data_serialization_large_body() {
686 let mut large_object = serde_json::Map::new();
687 for i in 0..100 {
688 large_object.insert(format!("key_{}", i), serde_json::Value::String(format!("value_{}", i)));
689 }
690
691 let data = RequestData {
692 body: std::sync::Arc::new(Value::Object(large_object)),
693 ..minimal_request_data()
694 };
695
696 let json = serde_json::to_value(&data).expect("serialization failed");
697
698 assert!(json["body"].is_object());
699 assert_eq!(json["body"].get("key_0").unwrap(), "value_0");
700 assert_eq!(json["body"].get("key_99").unwrap(), "value_99");
701 }
702
703 #[test]
704 fn test_request_data_empty_collections() {
705 let data = RequestData {
706 path_params: std::sync::Arc::new(HashMap::new()),
707 query_params: std::sync::Arc::new(Value::Object(serde_json::Map::new())),
708 validated_params: None,
709 raw_query_params: std::sync::Arc::new(HashMap::new()),
710 body: std::sync::Arc::new(Value::Object(serde_json::Map::new())),
711 raw_body: None,
712 headers: std::sync::Arc::new(HashMap::new()),
713 cookies: std::sync::Arc::new(HashMap::new()),
714 method: "GET".to_string(),
715 path: "/".to_string(),
716 #[cfg(feature = "di")]
717 dependencies: None,
718 };
719
720 let json = serde_json::to_value(&data).expect("serialization failed");
721
722 assert_eq!(json["path_params"].as_object().unwrap().len(), 0);
723 assert_eq!(json["query_params"].as_object().unwrap().len(), 0);
724 assert_eq!(json["raw_query_params"].as_object().unwrap().len(), 0);
725 assert_eq!(json["body"].as_object().unwrap().len(), 0);
726 assert!(json["raw_body"].is_null());
727 assert_eq!(json["headers"].as_object().unwrap().len(), 0);
728 assert_eq!(json["cookies"].as_object().unwrap().len(), 0);
729 }
730
731 #[test]
732 fn test_request_data_special_characters_in_strings() {
733 let mut headers = HashMap::new();
734 headers.insert("x-custom".to_string(), "value with \"quotes\"".to_string());
735 headers.insert("x-unicode".to_string(), "Café ☕ 🚀".to_string());
736
737 let data = RequestData {
738 method: "POST".to_string(),
739 path: "/api/v1/users\\test".to_string(),
740 headers: std::sync::Arc::new(headers),
741 body: std::sync::Arc::new(serde_json::json!({"note": "Contains\nnewline"})),
742 ..minimal_request_data()
743 };
744
745 let json = serde_json::to_value(&data).expect("serialization failed");
746
747 assert_eq!(json["headers"]["x-custom"], "value with \"quotes\"");
748 assert_eq!(json["headers"]["x-unicode"], "Café ☕ 🚀");
749 assert_eq!(json["path"], "/api/v1/users\\test");
750 assert_eq!(json["body"]["note"], "Contains\nnewline");
751 }
752
753 #[test]
754 #[cfg(feature = "di")]
755 fn test_request_data_serialization_with_di_feature_no_dependencies() {
756 let data = minimal_request_data();
757
758 let json = serde_json::to_value(&data).expect("serialization failed");
759
760 assert_eq!(json["has_dependencies"], false);
761 }
762
763 #[test]
764 fn test_request_data_method_variants() {
765 let methods = vec!["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"];
766
767 for method in methods {
768 let data = RequestData {
769 method: method.to_string(),
770 ..minimal_request_data()
771 };
772
773 let json = serde_json::to_value(&data).expect("serialization failed");
774
775 assert_eq!(json["method"], method);
776 }
777 }
778
779 #[test]
780 fn test_request_data_serialization_null_body() {
781 let data = RequestData {
782 body: std::sync::Arc::new(Value::Null),
783 ..minimal_request_data()
784 };
785
786 let json = serde_json::to_value(&data).expect("serialization failed");
787
788 assert!(json["body"].is_null());
789 }
790
791 #[test]
792 fn test_request_data_serialization_array_body() {
793 let data = RequestData {
794 body: std::sync::Arc::new(serde_json::json!([1, 2, 3, "four", {"five": 5}])),
795 ..minimal_request_data()
796 };
797
798 let json = serde_json::to_value(&data).expect("serialization failed");
799
800 assert!(json["body"].is_array());
801 assert_eq!(json["body"][0], 1);
802 assert_eq!(json["body"][1], 2);
803 assert_eq!(json["body"][3], "four");
804 assert_eq!(json["body"][4]["five"], 5);
805 }
806
807 #[test]
808 fn test_request_data_serialization_numeric_edge_cases() {
809 let data = RequestData {
810 body: std::sync::Arc::new(serde_json::json!({
811 "zero": 0,
812 "negative": -42,
813 "large": 9223372036854775807i64,
814 "float": 3.14159
815 })),
816 ..minimal_request_data()
817 };
818
819 let json = serde_json::to_value(&data).expect("serialization failed");
820
821 assert_eq!(json["body"]["zero"], 0);
822 assert_eq!(json["body"]["negative"], -42);
823 assert_eq!(json["body"]["large"], 9223372036854775807i64);
824 assert_eq!(json["body"]["float"], 3.14159);
825 }
826
827 #[test]
828 fn test_validated_params_basic_creation() {
829 let mut params = HashMap::new();
830 params.insert("id".to_string(), Value::String("123".to_string()));
831 params.insert("active".to_string(), Value::Bool(true));
832
833 let validated = ValidatedParams { params };
834
835 assert_eq!(validated.params.get("id").unwrap(), &Value::String("123".to_string()));
836 assert_eq!(validated.params.get("active").unwrap(), &Value::Bool(true));
837 }
838}