spikard 0.8.2 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -10
  3. data/ext/spikard_rb/Cargo.lock +234 -162
  4. data/ext/spikard_rb/Cargo.toml +3 -3
  5. data/ext/spikard_rb/extconf.rb +4 -3
  6. data/lib/spikard/config.rb +88 -12
  7. data/lib/spikard/testing.rb +3 -1
  8. data/lib/spikard/version.rb +1 -1
  9. data/lib/spikard.rb +11 -0
  10. data/vendor/crates/spikard-bindings-shared/Cargo.toml +11 -6
  11. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +8 -8
  12. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +63 -25
  13. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +20 -4
  14. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +10 -4
  15. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +25 -22
  16. data/vendor/crates/spikard-bindings-shared/src/grpc_metadata.rs +14 -12
  17. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +24 -10
  18. data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +829 -0
  19. data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +587 -0
  20. data/vendor/crates/spikard-bindings-shared/src/lib.rs +7 -0
  21. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +17 -11
  22. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +51 -73
  23. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +442 -4
  24. data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +944 -0
  25. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +22 -10
  26. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +28 -10
  27. data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +3 -2
  28. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +13 -13
  29. data/vendor/crates/spikard-bindings-shared/tests/{comprehensive_coverage.rs → full_coverage.rs} +10 -5
  30. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +14 -14
  31. data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +669 -0
  32. data/vendor/crates/spikard-core/Cargo.toml +11 -3
  33. data/vendor/crates/spikard-core/src/bindings/response.rs +6 -9
  34. data/vendor/crates/spikard-core/src/debug.rs +2 -2
  35. data/vendor/crates/spikard-core/src/di/container.rs +2 -2
  36. data/vendor/crates/spikard-core/src/di/error.rs +1 -1
  37. data/vendor/crates/spikard-core/src/di/factory.rs +9 -5
  38. data/vendor/crates/spikard-core/src/di/graph.rs +1 -0
  39. data/vendor/crates/spikard-core/src/di/resolved.rs +25 -2
  40. data/vendor/crates/spikard-core/src/di/value.rs +2 -1
  41. data/vendor/crates/spikard-core/src/errors.rs +3 -0
  42. data/vendor/crates/spikard-core/src/http.rs +94 -18
  43. data/vendor/crates/spikard-core/src/lifecycle.rs +85 -61
  44. data/vendor/crates/spikard-core/src/parameters.rs +75 -54
  45. data/vendor/crates/spikard-core/src/problem.rs +19 -5
  46. data/vendor/crates/spikard-core/src/request_data.rs +16 -24
  47. data/vendor/crates/spikard-core/src/router.rs +26 -6
  48. data/vendor/crates/spikard-core/src/schema_registry.rs +25 -11
  49. data/vendor/crates/spikard-core/src/type_hints.rs +14 -7
  50. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +30 -16
  51. data/vendor/crates/spikard-core/src/validation/mod.rs +46 -33
  52. data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +1 -1
  53. data/vendor/crates/spikard-core/tests/error_mapper.rs +2 -2
  54. data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +1 -1
  55. data/vendor/crates/spikard-core/tests/parameters_full.rs +1 -1
  56. data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +1 -1
  57. data/vendor/crates/spikard-core/tests/validation_coverage.rs +4 -4
  58. data/vendor/crates/spikard-http/Cargo.toml +11 -2
  59. data/vendor/crates/spikard-http/src/cors.rs +32 -11
  60. data/vendor/crates/spikard-http/src/di_handler.rs +12 -8
  61. data/vendor/crates/spikard-http/src/grpc/framing.rs +469 -0
  62. data/vendor/crates/spikard-http/src/grpc/handler.rs +887 -25
  63. data/vendor/crates/spikard-http/src/grpc/mod.rs +114 -22
  64. data/vendor/crates/spikard-http/src/grpc/service.rs +232 -2
  65. data/vendor/crates/spikard-http/src/grpc/streaming.rs +80 -2
  66. data/vendor/crates/spikard-http/src/handler_trait.rs +204 -27
  67. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +15 -15
  68. data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +2 -2
  69. data/vendor/crates/spikard-http/src/jsonrpc/router.rs +2 -2
  70. data/vendor/crates/spikard-http/src/lib.rs +1 -1
  71. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +2 -2
  72. data/vendor/crates/spikard-http/src/lifecycle.rs +4 -4
  73. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +2 -0
  74. data/vendor/crates/spikard-http/src/server/fast_router.rs +186 -0
  75. data/vendor/crates/spikard-http/src/server/grpc_routing.rs +324 -23
  76. data/vendor/crates/spikard-http/src/server/handler.rs +33 -22
  77. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +21 -2
  78. data/vendor/crates/spikard-http/src/server/mod.rs +125 -20
  79. data/vendor/crates/spikard-http/src/server/request_extraction.rs +126 -44
  80. data/vendor/crates/spikard-http/src/server/routing_factory.rs +80 -69
  81. data/vendor/crates/spikard-http/tests/common/handlers.rs +2 -2
  82. data/vendor/crates/spikard-http/tests/common/test_builders.rs +12 -12
  83. data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +2 -2
  84. data/vendor/crates/spikard-http/tests/di_integration.rs +6 -6
  85. data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +430 -0
  86. data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +738 -0
  87. data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +13 -9
  88. data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +974 -0
  89. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +2 -2
  90. data/vendor/crates/spikard-http/tests/request_extraction_full.rs +4 -4
  91. data/vendor/crates/spikard-http/tests/server_config_builder.rs +2 -2
  92. data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +1 -0
  93. data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +140 -0
  94. data/vendor/crates/spikard-rb/Cargo.toml +11 -1
  95. data/vendor/crates/spikard-rb/build.rs +1 -0
  96. data/vendor/crates/spikard-rb/src/conversion.rs +138 -4
  97. data/vendor/crates/spikard-rb/src/grpc/handler.rs +706 -229
  98. data/vendor/crates/spikard-rb/src/grpc/mod.rs +6 -2
  99. data/vendor/crates/spikard-rb/src/gvl.rs +2 -2
  100. data/vendor/crates/spikard-rb/src/handler.rs +169 -91
  101. data/vendor/crates/spikard-rb/src/lib.rs +502 -62
  102. data/vendor/crates/spikard-rb/src/lifecycle.rs +31 -3
  103. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +108 -43
  104. data/vendor/crates/spikard-rb/src/request.rs +117 -20
  105. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +52 -25
  106. data/vendor/crates/spikard-rb/src/server.rs +23 -14
  107. data/vendor/crates/spikard-rb/src/testing/client.rs +5 -4
  108. data/vendor/crates/spikard-rb/src/testing/sse.rs +1 -36
  109. data/vendor/crates/spikard-rb/src/testing/websocket.rs +3 -38
  110. data/vendor/crates/spikard-rb/src/websocket.rs +32 -23
  111. data/vendor/crates/spikard-rb-macros/Cargo.toml +9 -1
  112. data/vendor/crates/spikard-rb-macros/src/lib.rs +4 -5
  113. metadata +14 -4
  114. data/vendor/bundle/ruby/3.4.0/gems/diff-lcs-1.6.2/mise.toml +0 -5
  115. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.10.0/build/buildkitd.toml +0 -2
@@ -203,7 +203,7 @@ fn boolean_empty_string_is_coerced_to_false() {
203
203
 
204
204
  let validator = ParameterValidator::new(schema).expect("validator");
205
205
  let mut raw_query = HashMap::new();
206
- raw_query.insert("flag".to_string(), vec!["".to_string()]);
206
+ raw_query.insert("flag".to_string(), vec![String::new()]);
207
207
 
208
208
  let extracted = validator
209
209
  .validate_and_extract(
@@ -32,10 +32,10 @@ fn validator_preprocesses_binary_file_objects_recursively() {
32
32
  });
33
33
 
34
34
  let data = json!({
35
- "file": file_object.clone(),
36
- "files": [file_object.clone()],
35
+ "file": &file_object,
36
+ "files": [&file_object],
37
37
  "nested": {
38
- "inner": file_object,
38
+ "inner": &file_object,
39
39
  "other": 1
40
40
  }
41
41
  });
@@ -242,7 +242,7 @@ fn error_mapper_uses_schema_constraints_when_present() {
242
242
 
243
243
  let (ty, _msg, ctx) = ErrorMapper::map_error(&ErrorCondition::EmailFormat, &schema, "/properties/value", "generic");
244
244
  assert_eq!(ty, "string_pattern_mismatch");
245
- assert!(ctx.as_ref().unwrap()["pattern"].as_str().unwrap().contains("@"));
245
+ assert!(ctx.as_ref().unwrap()["pattern"].as_str().unwrap().contains('@'));
246
246
 
247
247
  let (ty, _msg, ctx) = ErrorMapper::map_error(&ErrorCondition::UuidFormat, &schema, "/properties/value", "generic");
248
248
  assert_eq!(ty, "uuid_parsing");
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "spikard-http"
3
- version = "0.8.2"
3
+ version = "0.10.1"
4
4
  edition = "2024"
5
5
  authors = ["Na'aman Hirschfeld <nhirschfeld@gmail.com>"]
6
6
  license = "MIT"
@@ -16,6 +16,7 @@ readme = "README.md"
16
16
  axum = { version = "0.8", features = ["multipart", "ws"] }
17
17
  tokio = { version = "1", features = ["full"] }
18
18
  tokio-util = "0.7"
19
+ tokio-stream = "0.1"
19
20
  tower = "0.5"
20
21
  tower-http = { version = "0.6.8", features = ["fs", "trace", "compression-gzip", "compression-br", "compression-deflate", "cors", "request-id", "limit", "timeout", "set-header", "sensitive-headers"] }
21
22
  tower_governor = "0.8"
@@ -40,7 +41,8 @@ urlencoding = "2.1"
40
41
  url = "2.5"
41
42
  mime = "0.3"
42
43
  jiff = "0.2"
43
- uuid = "1.19"
44
+ uuid = "1.20"
45
+ ahash = "0.8"
44
46
  bytes = "1.11"
45
47
  http-body-util = "0.1"
46
48
  http-body = "1.0"
@@ -55,6 +57,13 @@ prost = "0.14"
55
57
  prost-types = "0.14"
56
58
  h2 = "0.4"
57
59
 
60
+ [lints.rust]
61
+ unexpected_cfgs = { level = "allow", check-cfg = ['cfg(tarpaulin_include)'] }
62
+
63
+ [lints.clippy]
64
+ all = { level = "deny", priority = 0 }
65
+ pedantic = { level = "deny", priority = 0 }
66
+ nursery = { level = "deny", priority = 0 }
58
67
 
59
68
  [features]
60
69
  default = []
@@ -56,15 +56,16 @@ fn is_method_allowed(method: &str, allowed_methods: &[String]) -> bool {
56
56
  ///
57
57
  /// # Returns
58
58
  /// `true` if all requested headers are allowed, `false` if any header is not allowed
59
- fn are_headers_allowed(requested: &[&str], allowed: &[String]) -> bool {
59
+ fn are_headers_allowed(requested: impl IntoIterator<Item = impl AsRef<str>>, allowed: &[String]) -> bool {
60
60
  if allowed.iter().any(|h| h == "*") {
61
61
  return true;
62
62
  }
63
63
 
64
- requested.iter().all(|req_header| {
64
+ requested.into_iter().all(|req_header| {
65
+ let req_str = req_header.as_ref();
65
66
  allowed
66
67
  .iter()
67
- .any(|allowed_header| allowed_header.eq_ignore_ascii_case(req_header))
68
+ .any(|allowed_header| allowed_header.eq_ignore_ascii_case(req_str))
68
69
  })
69
70
  }
70
71
 
@@ -133,9 +134,8 @@ pub fn handle_preflight(headers: &HeaderMap, cors_config: &CorsConfig) -> Result
133
134
  .and_then(|v| v.to_str().ok());
134
135
 
135
136
  if let Some(req_headers) = requested_headers_str {
136
- let requested_headers: Vec<&str> = req_headers.split(',').map(|h| h.trim()).collect();
137
-
138
- if !are_headers_allowed(&requested_headers, &cors_config.allowed_headers) {
137
+ // Pass iterator directly without collecting into Vec
138
+ if !are_headers_allowed(req_headers.split(',').map(|h| h.trim()), &cors_config.allowed_headers) {
139
139
  return Err(Box::new((StatusCode::FORBIDDEN).into_response()));
140
140
  }
141
141
  }
@@ -162,16 +162,16 @@ pub fn handle_preflight(headers: &HeaderMap, cors_config: &CorsConfig) -> Result
162
162
  HeaderValue::from_str(origin).unwrap_or_else(|_| HeaderValue::from_static("*")),
163
163
  );
164
164
 
165
- let methods = cors_config.allowed_methods.join(", ");
165
+ let methods = cors_config.allowed_methods_joined();
166
166
  headers_mut.insert(
167
167
  "access-control-allow-methods",
168
- HeaderValue::from_str(&methods).unwrap_or_else(|_| HeaderValue::from_static("*")),
168
+ HeaderValue::from_str(methods).unwrap_or_else(|_| HeaderValue::from_static("*")),
169
169
  );
170
170
 
171
- let allowed_headers = cors_config.allowed_headers.join(", ");
171
+ let allowed_headers = cors_config.allowed_headers_joined();
172
172
  headers_mut.insert(
173
173
  "access-control-allow-headers",
174
- HeaderValue::from_str(&allowed_headers).unwrap_or_else(|_| HeaderValue::from_static("*")),
174
+ HeaderValue::from_str(allowed_headers).unwrap_or_else(|_| HeaderValue::from_static("*")),
175
175
  );
176
176
 
177
177
  if let Some(max_age) = cors_config.max_age
@@ -291,6 +291,7 @@ mod tests {
291
291
  expose_headers: Some(vec!["x-custom-header".to_string()]),
292
292
  max_age: Some(3600),
293
293
  allow_credentials: Some(true),
294
+ ..Default::default()
294
295
  }
295
296
  }
296
297
 
@@ -500,7 +501,8 @@ mod tests {
500
501
  allowed_headers: vec![],
501
502
  expose_headers: None,
502
503
  max_age: None,
503
- allow_credentials: Some(true), // SECURITY BUG: This should not be allowed with wildcard
504
+ allow_credentials: Some(true), // SECURITY BUG: This should not be allowed with wildcard,
505
+ ..Default::default()
504
506
  };
505
507
 
506
508
  let mut headers = HeaderMap::new();
@@ -538,6 +540,7 @@ mod tests {
538
540
  expose_headers: None,
539
541
  max_age: None,
540
542
  allow_credentials: None,
543
+ ..Default::default()
541
544
  };
542
545
 
543
546
  assert!(!is_origin_allowed("https://api.example.com", &config.allowed_origins));
@@ -561,6 +564,7 @@ mod tests {
561
564
  expose_headers: None,
562
565
  max_age: None,
563
566
  allow_credentials: None,
567
+ ..Default::default()
564
568
  };
565
569
 
566
570
  assert!(!is_origin_allowed("http://localhost:3001", &config.allowed_origins));
@@ -581,6 +585,7 @@ mod tests {
581
585
  expose_headers: None,
582
586
  max_age: None,
583
587
  allow_credentials: None,
588
+ ..Default::default()
584
589
  };
585
590
 
586
591
  assert!(!is_origin_allowed("http://example.com", &config.allowed_origins));
@@ -601,6 +606,7 @@ mod tests {
601
606
  expose_headers: None,
602
607
  max_age: None,
603
608
  allow_credentials: None,
609
+ ..Default::default()
604
610
  };
605
611
 
606
612
  assert!(!is_origin_allowed("https://example.com", &config.allowed_origins));
@@ -620,6 +626,7 @@ mod tests {
620
626
  expose_headers: None,
621
627
  max_age: None,
622
628
  allow_credentials: None,
629
+ ..Default::default()
623
630
  };
624
631
 
625
632
  assert!(!is_origin_allowed("https://example.com/", &config.allowed_origins));
@@ -640,6 +647,7 @@ mod tests {
640
647
  expose_headers: None,
641
648
  max_age: None,
642
649
  allow_credentials: None,
650
+ ..Default::default()
643
651
  };
644
652
 
645
653
  // SECURITY NOTE: "null" origin is allowed by wildcard in current implementation
@@ -652,6 +660,7 @@ mod tests {
652
660
  expose_headers: None,
653
661
  max_age: None,
654
662
  allow_credentials: None,
663
+ ..Default::default()
655
664
  };
656
665
  assert!(is_origin_allowed("null", &with_explicit_null.allowed_origins));
657
666
  }
@@ -666,6 +675,7 @@ mod tests {
666
675
  expose_headers: None,
667
676
  max_age: None,
668
677
  allow_credentials: None,
678
+ ..Default::default()
669
679
  };
670
680
  assert!(!is_origin_allowed("", &config_with_wildcard.allowed_origins));
671
681
 
@@ -676,6 +686,7 @@ mod tests {
676
686
  expose_headers: None,
677
687
  max_age: None,
678
688
  allow_credentials: None,
689
+ ..Default::default()
679
690
  };
680
691
  assert!(!is_origin_allowed("", &config_with_explicit.allowed_origins));
681
692
  }
@@ -705,6 +716,7 @@ mod tests {
705
716
  expose_headers: None,
706
717
  max_age: None,
707
718
  allow_credentials: None,
719
+ ..Default::default()
708
720
  };
709
721
 
710
722
  assert!(is_origin_allowed("https://trusted1.com", &config.allowed_origins));
@@ -728,6 +740,7 @@ mod tests {
728
740
  expose_headers: None,
729
741
  max_age: None,
730
742
  allow_credentials: None,
743
+ ..Default::default()
731
744
  };
732
745
 
733
746
  assert!(is_origin_allowed("https://example.com", &config.allowed_origins));
@@ -747,6 +760,7 @@ mod tests {
747
760
  expose_headers: None,
748
761
  max_age: Some(3600),
749
762
  allow_credentials: Some(false),
763
+ ..Default::default()
750
764
  };
751
765
 
752
766
  let mut headers = HeaderMap::new();
@@ -798,6 +812,7 @@ mod tests {
798
812
  expose_headers: None,
799
813
  max_age: None,
800
814
  allow_credentials: None,
815
+ ..Default::default()
801
816
  };
802
817
 
803
818
  let test_cases = vec![
@@ -836,6 +851,7 @@ mod tests {
836
851
  expose_headers: None,
837
852
  max_age: None,
838
853
  allow_credentials: None,
854
+ ..Default::default()
839
855
  };
840
856
 
841
857
  let test_cases = vec![
@@ -883,6 +899,7 @@ mod tests {
883
899
  expose_headers: Some(vec!["x-custom".to_string()]),
884
900
  max_age: None,
885
901
  allow_credentials: Some(true),
902
+ ..Default::default()
886
903
  };
887
904
 
888
905
  let mut response = Response::new(Body::empty());
@@ -908,6 +925,7 @@ mod tests {
908
925
  expose_headers: None,
909
926
  max_age: None,
910
927
  allow_credentials: None,
928
+ ..Default::default()
911
929
  };
912
930
 
913
931
  let mut headers = HeaderMap::new();
@@ -943,6 +961,7 @@ mod tests {
943
961
  expose_headers: None,
944
962
  max_age: None,
945
963
  allow_credentials: None,
964
+ ..Default::default()
946
965
  };
947
966
 
948
967
  let test_cases = vec!["GET", "get", "Get", "POST", "post"];
@@ -971,6 +990,7 @@ mod tests {
971
990
  expose_headers: None,
972
991
  max_age: Some(7200),
973
992
  allow_credentials: None,
993
+ ..Default::default()
974
994
  };
975
995
 
976
996
  let mut headers = HeaderMap::new();
@@ -995,6 +1015,7 @@ mod tests {
995
1015
  expose_headers: None,
996
1016
  max_age: None,
997
1017
  allow_credentials: None,
1018
+ ..Default::default()
998
1019
  };
999
1020
 
1000
1021
  assert!(!is_origin_allowed("https://api.example.com", &config.allowed_origins));
@@ -153,10 +153,14 @@ impl Handler for DependencyInjectingHandler {
153
153
 
154
154
  let core_request_data = spikard_core::RequestData {
155
155
  path_params: Arc::clone(&request_data.path_params),
156
- query_params: request_data.query_params.clone(),
157
- validated_params: request_data.validated_params.clone(),
156
+ query_params: Arc::try_unwrap(Arc::clone(&request_data.query_params))
157
+ .unwrap_or_else(|arc| (*arc).clone()),
158
+ validated_params: request_data
159
+ .validated_params
160
+ .as_ref()
161
+ .map(|arc| Arc::try_unwrap(Arc::clone(arc)).unwrap_or_else(|a| (*a).clone())),
158
162
  raw_query_params: Arc::clone(&request_data.raw_query_params),
159
- body: request_data.body.clone(),
163
+ body: Arc::try_unwrap(Arc::clone(&request_data.body)).unwrap_or_else(|arc| (*arc).clone()),
160
164
  raw_body: request_data.raw_body.clone(),
161
165
  headers: Arc::clone(&request_data.headers),
162
166
  cookies: Arc::clone(&request_data.cookies),
@@ -346,10 +350,10 @@ mod tests {
346
350
  fn create_request_data() -> RequestData {
347
351
  RequestData {
348
352
  path_params: Arc::new(HashMap::new()),
349
- query_params: serde_json::Value::Null,
353
+ query_params: Arc::new(serde_json::Value::Null),
350
354
  validated_params: None,
351
355
  raw_query_params: Arc::new(HashMap::new()),
352
- body: serde_json::Value::Null,
356
+ body: Arc::new(serde_json::Value::Null),
353
357
  raw_body: None,
354
358
  headers: Arc::new(HashMap::new()),
355
359
  cookies: Arc::new(HashMap::new()),
@@ -1163,7 +1167,7 @@ mod tests {
1163
1167
  .unwrap();
1164
1168
  let mut request_data = create_request_data();
1165
1169
  request_data.method = "POST".to_string();
1166
- request_data.body = serde_json::json!({"key": "value"});
1170
+ request_data.body = Arc::new(serde_json::json!({"key": "value"}));
1167
1171
 
1168
1172
  let result = di_handler.call(request, request_data).await;
1169
1173
 
@@ -1602,10 +1606,10 @@ mod tests {
1602
1606
 
1603
1607
  let request_data = RequestData {
1604
1608
  path_params: Arc::new(path_params.clone()),
1605
- query_params: serde_json::json!({"filter": "active", "sort": "name"}),
1609
+ query_params: Arc::new(serde_json::json!({"filter": "active", "sort": "name"})),
1606
1610
  validated_params: None,
1607
1611
  raw_query_params: Arc::new(raw_query_params.clone()),
1608
- body: serde_json::json!({"name": "John", "email": "john@example.com"}),
1612
+ body: Arc::new(serde_json::json!({"name": "John", "email": "john@example.com"})),
1609
1613
  raw_body: Some(bytes::Bytes::from(r#"{"name":"John","email":"john@example.com"}"#)),
1610
1614
  headers: Arc::new(headers.clone()),
1611
1615
  cookies: Arc::new(cookies.clone()),