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