spikard 0.4.0-x64-mingw-ucrt

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 (138) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -0
  3. data/README.md +659 -0
  4. data/ext/spikard_rb/Cargo.toml +17 -0
  5. data/ext/spikard_rb/extconf.rb +10 -0
  6. data/ext/spikard_rb/src/lib.rs +6 -0
  7. data/lib/spikard/app.rb +405 -0
  8. data/lib/spikard/background.rb +27 -0
  9. data/lib/spikard/config.rb +396 -0
  10. data/lib/spikard/converters.rb +13 -0
  11. data/lib/spikard/handler_wrapper.rb +113 -0
  12. data/lib/spikard/provide.rb +214 -0
  13. data/lib/spikard/response.rb +173 -0
  14. data/lib/spikard/schema.rb +243 -0
  15. data/lib/spikard/sse.rb +111 -0
  16. data/lib/spikard/streaming_response.rb +44 -0
  17. data/lib/spikard/testing.rb +221 -0
  18. data/lib/spikard/upload_file.rb +131 -0
  19. data/lib/spikard/version.rb +5 -0
  20. data/lib/spikard/websocket.rb +59 -0
  21. data/lib/spikard.rb +43 -0
  22. data/sig/spikard.rbs +366 -0
  23. data/vendor/bundle/ruby/3.4.0/gems/diff-lcs-1.6.2/mise.toml +5 -0
  24. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.10.0/build/buildkitd.toml +2 -0
  25. data/vendor/crates/spikard-bindings-shared/Cargo.toml +63 -0
  26. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +139 -0
  27. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +561 -0
  28. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +194 -0
  29. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +246 -0
  30. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +403 -0
  31. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +274 -0
  32. data/vendor/crates/spikard-bindings-shared/src/lib.rs +25 -0
  33. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +298 -0
  34. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +637 -0
  35. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +309 -0
  36. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +248 -0
  37. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +355 -0
  38. data/vendor/crates/spikard-bindings-shared/tests/comprehensive_coverage.rs +502 -0
  39. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +389 -0
  40. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +413 -0
  41. data/vendor/crates/spikard-core/Cargo.toml +40 -0
  42. data/vendor/crates/spikard-core/src/bindings/mod.rs +3 -0
  43. data/vendor/crates/spikard-core/src/bindings/response.rs +133 -0
  44. data/vendor/crates/spikard-core/src/debug.rs +63 -0
  45. data/vendor/crates/spikard-core/src/di/container.rs +726 -0
  46. data/vendor/crates/spikard-core/src/di/dependency.rs +273 -0
  47. data/vendor/crates/spikard-core/src/di/error.rs +118 -0
  48. data/vendor/crates/spikard-core/src/di/factory.rs +538 -0
  49. data/vendor/crates/spikard-core/src/di/graph.rs +545 -0
  50. data/vendor/crates/spikard-core/src/di/mod.rs +192 -0
  51. data/vendor/crates/spikard-core/src/di/resolved.rs +411 -0
  52. data/vendor/crates/spikard-core/src/di/value.rs +283 -0
  53. data/vendor/crates/spikard-core/src/errors.rs +39 -0
  54. data/vendor/crates/spikard-core/src/http.rs +153 -0
  55. data/vendor/crates/spikard-core/src/lib.rs +29 -0
  56. data/vendor/crates/spikard-core/src/lifecycle.rs +422 -0
  57. data/vendor/crates/spikard-core/src/metadata.rs +397 -0
  58. data/vendor/crates/spikard-core/src/parameters.rs +723 -0
  59. data/vendor/crates/spikard-core/src/problem.rs +310 -0
  60. data/vendor/crates/spikard-core/src/request_data.rs +189 -0
  61. data/vendor/crates/spikard-core/src/router.rs +249 -0
  62. data/vendor/crates/spikard-core/src/schema_registry.rs +183 -0
  63. data/vendor/crates/spikard-core/src/type_hints.rs +304 -0
  64. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +689 -0
  65. data/vendor/crates/spikard-core/src/validation/mod.rs +459 -0
  66. data/vendor/crates/spikard-http/Cargo.toml +58 -0
  67. data/vendor/crates/spikard-http/examples/sse-notifications.rs +147 -0
  68. data/vendor/crates/spikard-http/examples/websocket-chat.rs +91 -0
  69. data/vendor/crates/spikard-http/src/auth.rs +247 -0
  70. data/vendor/crates/spikard-http/src/background.rs +1562 -0
  71. data/vendor/crates/spikard-http/src/bindings/mod.rs +3 -0
  72. data/vendor/crates/spikard-http/src/bindings/response.rs +1 -0
  73. data/vendor/crates/spikard-http/src/body_metadata.rs +8 -0
  74. data/vendor/crates/spikard-http/src/cors.rs +490 -0
  75. data/vendor/crates/spikard-http/src/debug.rs +63 -0
  76. data/vendor/crates/spikard-http/src/di_handler.rs +1878 -0
  77. data/vendor/crates/spikard-http/src/handler_response.rs +532 -0
  78. data/vendor/crates/spikard-http/src/handler_trait.rs +861 -0
  79. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +284 -0
  80. data/vendor/crates/spikard-http/src/lib.rs +524 -0
  81. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +149 -0
  82. data/vendor/crates/spikard-http/src/lifecycle.rs +428 -0
  83. data/vendor/crates/spikard-http/src/middleware/mod.rs +285 -0
  84. data/vendor/crates/spikard-http/src/middleware/multipart.rs +930 -0
  85. data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +541 -0
  86. data/vendor/crates/spikard-http/src/middleware/validation.rs +287 -0
  87. data/vendor/crates/spikard-http/src/openapi/mod.rs +309 -0
  88. data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +535 -0
  89. data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +867 -0
  90. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +678 -0
  91. data/vendor/crates/spikard-http/src/query_parser.rs +369 -0
  92. data/vendor/crates/spikard-http/src/response.rs +399 -0
  93. data/vendor/crates/spikard-http/src/server/handler.rs +1557 -0
  94. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +98 -0
  95. data/vendor/crates/spikard-http/src/server/mod.rs +806 -0
  96. data/vendor/crates/spikard-http/src/server/request_extraction.rs +630 -0
  97. data/vendor/crates/spikard-http/src/server/routing_factory.rs +497 -0
  98. data/vendor/crates/spikard-http/src/sse.rs +961 -0
  99. data/vendor/crates/spikard-http/src/testing/form.rs +14 -0
  100. data/vendor/crates/spikard-http/src/testing/multipart.rs +60 -0
  101. data/vendor/crates/spikard-http/src/testing/test_client.rs +285 -0
  102. data/vendor/crates/spikard-http/src/testing.rs +377 -0
  103. data/vendor/crates/spikard-http/src/websocket.rs +831 -0
  104. data/vendor/crates/spikard-http/tests/background_behavior.rs +918 -0
  105. data/vendor/crates/spikard-http/tests/common/handlers.rs +308 -0
  106. data/vendor/crates/spikard-http/tests/common/mod.rs +21 -0
  107. data/vendor/crates/spikard-http/tests/di_integration.rs +202 -0
  108. data/vendor/crates/spikard-http/tests/doc_snippets.rs +4 -0
  109. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +1135 -0
  110. data/vendor/crates/spikard-http/tests/multipart_behavior.rs +688 -0
  111. data/vendor/crates/spikard-http/tests/server_config_builder.rs +324 -0
  112. data/vendor/crates/spikard-http/tests/sse_behavior.rs +728 -0
  113. data/vendor/crates/spikard-http/tests/websocket_behavior.rs +724 -0
  114. data/vendor/crates/spikard-rb/Cargo.toml +43 -0
  115. data/vendor/crates/spikard-rb/build.rs +199 -0
  116. data/vendor/crates/spikard-rb/src/background.rs +63 -0
  117. data/vendor/crates/spikard-rb/src/config/mod.rs +5 -0
  118. data/vendor/crates/spikard-rb/src/config/server_config.rs +283 -0
  119. data/vendor/crates/spikard-rb/src/conversion.rs +459 -0
  120. data/vendor/crates/spikard-rb/src/di/builder.rs +105 -0
  121. data/vendor/crates/spikard-rb/src/di/mod.rs +413 -0
  122. data/vendor/crates/spikard-rb/src/handler.rs +612 -0
  123. data/vendor/crates/spikard-rb/src/integration/mod.rs +3 -0
  124. data/vendor/crates/spikard-rb/src/lib.rs +1857 -0
  125. data/vendor/crates/spikard-rb/src/lifecycle.rs +275 -0
  126. data/vendor/crates/spikard-rb/src/metadata/mod.rs +5 -0
  127. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +427 -0
  128. data/vendor/crates/spikard-rb/src/runtime/mod.rs +5 -0
  129. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +326 -0
  130. data/vendor/crates/spikard-rb/src/server.rs +283 -0
  131. data/vendor/crates/spikard-rb/src/sse.rs +231 -0
  132. data/vendor/crates/spikard-rb/src/testing/client.rs +404 -0
  133. data/vendor/crates/spikard-rb/src/testing/mod.rs +7 -0
  134. data/vendor/crates/spikard-rb/src/testing/sse.rs +143 -0
  135. data/vendor/crates/spikard-rb/src/testing/websocket.rs +221 -0
  136. data/vendor/crates/spikard-rb/src/websocket.rs +233 -0
  137. data/vendor/crates/spikard-rb/tests/magnus_ffi_tests.rs +14 -0
  138. metadata +213 -0
@@ -0,0 +1,497 @@
1
+ //! Method routing factory for consolidating HTTP method handler creation.
2
+ //!
3
+ //! This module provides a factory pattern to eliminate duplication in the
4
+ //! create_method_router function. It handles:
5
+ //! - Different HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE)
6
+ //! - Both path variants (with and without path parameters)
7
+ //! - Handler wrapping and request data extraction
8
+ //! - Lifecycle hook integration
9
+
10
+ use crate::handler_trait::Handler;
11
+ use axum::body::Body;
12
+ use axum::extract::{Path, Request as AxumRequest};
13
+ use axum::http::Request;
14
+ use axum::routing::MethodRouter;
15
+ use bytes::Bytes;
16
+ use std::collections::HashMap;
17
+ use std::sync::Arc;
18
+
19
+ use super::lifecycle_execution;
20
+ use super::request_extraction;
21
+
22
+ /// HTTP method type enumeration for routing
23
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
24
+ pub enum HttpMethod {
25
+ Get,
26
+ Post,
27
+ Put,
28
+ Patch,
29
+ Delete,
30
+ Head,
31
+ Trace,
32
+ Options,
33
+ }
34
+
35
+ impl HttpMethod {
36
+ /// Parse from string representation (e.g., "GET", "POST")
37
+ pub fn from_str(s: &str) -> Option<Self> {
38
+ match s {
39
+ "GET" => Some(HttpMethod::Get),
40
+ "POST" => Some(HttpMethod::Post),
41
+ "PUT" => Some(HttpMethod::Put),
42
+ "PATCH" => Some(HttpMethod::Patch),
43
+ "DELETE" => Some(HttpMethod::Delete),
44
+ "HEAD" => Some(HttpMethod::Head),
45
+ "TRACE" => Some(HttpMethod::Trace),
46
+ "OPTIONS" => Some(HttpMethod::Options),
47
+ _ => None,
48
+ }
49
+ }
50
+
51
+ /// Check if this method typically has a request body
52
+ pub fn expects_body(&self) -> bool {
53
+ matches!(self, HttpMethod::Post | HttpMethod::Put | HttpMethod::Patch)
54
+ }
55
+ }
56
+
57
+ /// Factory for creating method routers
58
+ pub struct MethodRouterFactory;
59
+
60
+ impl MethodRouterFactory {
61
+ /// Create a method router for the given HTTP method
62
+ ///
63
+ /// # Arguments
64
+ ///
65
+ /// * `method` - HTTP method string (e.g., "GET", "POST")
66
+ /// * `has_path_params` - Whether the route has path parameters
67
+ /// * `handler` - The request handler
68
+ /// * `hooks` - Optional lifecycle hooks
69
+ ///
70
+ /// # Returns
71
+ ///
72
+ /// A configured MethodRouter or an error if the method is unsupported
73
+ pub fn create(
74
+ method: &str,
75
+ has_path_params: bool,
76
+ handler: Arc<dyn Handler>,
77
+ hooks: Option<Arc<crate::LifecycleHooks>>,
78
+ ) -> Result<MethodRouter, String> {
79
+ let http_method = HttpMethod::from_str(method)
80
+ .ok_or_else(|| format!("[spikard-router] unsupported HTTP method: {}", method))?;
81
+
82
+ Ok(if has_path_params {
83
+ Self::create_with_path_params(http_method, handler, hooks)
84
+ } else {
85
+ Self::create_without_path_params(http_method, handler, hooks)
86
+ })
87
+ }
88
+
89
+ /// Create a method router for a route with path parameters
90
+ fn create_with_path_params(
91
+ method: HttpMethod,
92
+ handler: Arc<dyn Handler>,
93
+ hooks: Option<Arc<crate::LifecycleHooks>>,
94
+ ) -> MethodRouter {
95
+ let handler_clone = handler.clone();
96
+ let hooks_clone = hooks.clone();
97
+
98
+ if method.expects_body() {
99
+ match method {
100
+ HttpMethod::Post => {
101
+ let handler_clone = handler_clone.clone();
102
+ let hooks_clone = hooks_clone.clone();
103
+ axum::routing::post(
104
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
105
+ let handler = handler_clone.clone();
106
+ let hooks = hooks_clone.clone();
107
+ async move {
108
+ let (parts, body) = req.into_parts();
109
+ let request_data =
110
+ request_extraction::create_request_data_with_body(&parts, path_params.0, body)
111
+ .await?;
112
+ let mut req = Request::from_parts(
113
+ parts,
114
+ Body::from(request_data.raw_body.clone().unwrap_or_else(Bytes::new)),
115
+ );
116
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
117
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
118
+ .await
119
+ }
120
+ },
121
+ )
122
+ }
123
+ HttpMethod::Put => {
124
+ let handler_clone = handler_clone.clone();
125
+ let hooks_clone = hooks_clone.clone();
126
+ axum::routing::put(
127
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
128
+ let handler = handler_clone.clone();
129
+ let hooks = hooks_clone.clone();
130
+ async move {
131
+ let (parts, body) = req.into_parts();
132
+ let request_data =
133
+ request_extraction::create_request_data_with_body(&parts, path_params.0, body)
134
+ .await?;
135
+ let mut req = Request::from_parts(
136
+ parts,
137
+ Body::from(request_data.raw_body.clone().unwrap_or_else(Bytes::new)),
138
+ );
139
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
140
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
141
+ .await
142
+ }
143
+ },
144
+ )
145
+ }
146
+ HttpMethod::Patch => {
147
+ let handler_clone = handler_clone.clone();
148
+ let hooks_clone = hooks_clone.clone();
149
+ axum::routing::patch(
150
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
151
+ let handler = handler_clone.clone();
152
+ let hooks = hooks_clone.clone();
153
+ async move {
154
+ let (parts, body) = req.into_parts();
155
+ let request_data =
156
+ request_extraction::create_request_data_with_body(&parts, path_params.0, body)
157
+ .await?;
158
+ let mut req = Request::from_parts(
159
+ parts,
160
+ Body::from(request_data.raw_body.clone().unwrap_or_else(Bytes::new)),
161
+ );
162
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
163
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
164
+ .await
165
+ }
166
+ },
167
+ )
168
+ }
169
+ _ => MethodRouter::new(),
170
+ }
171
+ } else {
172
+ match method {
173
+ HttpMethod::Get => {
174
+ let handler_clone = handler_clone.clone();
175
+ let hooks_clone = hooks_clone.clone();
176
+ axum::routing::get(
177
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
178
+ let handler = handler_clone.clone();
179
+ let hooks = hooks_clone.clone();
180
+ async move {
181
+ let request_data = request_extraction::create_request_data_without_body(
182
+ req.uri(),
183
+ req.method(),
184
+ req.headers(),
185
+ path_params.0,
186
+ );
187
+ let mut req = req;
188
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
189
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
190
+ .await
191
+ }
192
+ },
193
+ )
194
+ }
195
+ HttpMethod::Delete => {
196
+ let handler_clone = handler_clone.clone();
197
+ let hooks_clone = hooks_clone.clone();
198
+ axum::routing::delete(
199
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
200
+ let handler = handler_clone.clone();
201
+ let hooks = hooks_clone.clone();
202
+ async move {
203
+ let request_data = request_extraction::create_request_data_without_body(
204
+ req.uri(),
205
+ req.method(),
206
+ req.headers(),
207
+ path_params.0,
208
+ );
209
+ let mut req = req;
210
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
211
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
212
+ .await
213
+ }
214
+ },
215
+ )
216
+ }
217
+ HttpMethod::Head => {
218
+ let handler_clone = handler_clone.clone();
219
+ let hooks_clone = hooks_clone.clone();
220
+ axum::routing::head(
221
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
222
+ let handler = handler_clone.clone();
223
+ let hooks = hooks_clone.clone();
224
+ async move {
225
+ let request_data = request_extraction::create_request_data_without_body(
226
+ req.uri(),
227
+ req.method(),
228
+ req.headers(),
229
+ path_params.0,
230
+ );
231
+ let mut req = req;
232
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
233
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
234
+ .await
235
+ }
236
+ },
237
+ )
238
+ }
239
+ HttpMethod::Trace => {
240
+ let handler_clone = handler_clone.clone();
241
+ let hooks_clone = hooks_clone.clone();
242
+ axum::routing::trace(
243
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
244
+ let handler = handler_clone.clone();
245
+ let hooks = hooks_clone.clone();
246
+ async move {
247
+ let request_data = request_extraction::create_request_data_without_body(
248
+ req.uri(),
249
+ req.method(),
250
+ req.headers(),
251
+ path_params.0,
252
+ );
253
+ let mut req = req;
254
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
255
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
256
+ .await
257
+ }
258
+ },
259
+ )
260
+ }
261
+ HttpMethod::Options => {
262
+ let handler_clone = handler_clone.clone();
263
+ let hooks_clone = hooks_clone.clone();
264
+ axum::routing::options(
265
+ move |path_params: Path<HashMap<String, String>>, req: AxumRequest| {
266
+ let handler = handler_clone.clone();
267
+ let hooks = hooks_clone.clone();
268
+ async move {
269
+ let request_data = request_extraction::create_request_data_without_body(
270
+ req.uri(),
271
+ req.method(),
272
+ req.headers(),
273
+ path_params.0,
274
+ );
275
+ let mut req = req;
276
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
277
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
278
+ .await
279
+ }
280
+ },
281
+ )
282
+ }
283
+ _ => MethodRouter::new(),
284
+ }
285
+ }
286
+ }
287
+
288
+ /// Create a method router for a route without path parameters
289
+ fn create_without_path_params(
290
+ method: HttpMethod,
291
+ handler: Arc<dyn Handler>,
292
+ hooks: Option<Arc<crate::LifecycleHooks>>,
293
+ ) -> MethodRouter {
294
+ let handler_clone = handler.clone();
295
+ let hooks_clone = hooks.clone();
296
+
297
+ if method.expects_body() {
298
+ match method {
299
+ HttpMethod::Post => {
300
+ let handler_clone = handler_clone.clone();
301
+ let hooks_clone = hooks_clone.clone();
302
+ axum::routing::post(move |req: AxumRequest| {
303
+ let handler = handler_clone.clone();
304
+ let hooks = hooks_clone.clone();
305
+ async move {
306
+ let (parts, body) = req.into_parts();
307
+ let request_data =
308
+ request_extraction::create_request_data_with_body(&parts, HashMap::new(), body).await?;
309
+ let mut req = Request::from_parts(
310
+ parts,
311
+ Body::from(request_data.raw_body.clone().unwrap_or_else(Bytes::new)),
312
+ );
313
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
314
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
315
+ .await
316
+ }
317
+ })
318
+ }
319
+ HttpMethod::Put => {
320
+ let handler_clone = handler_clone.clone();
321
+ let hooks_clone = hooks_clone.clone();
322
+ axum::routing::put(move |req: AxumRequest| {
323
+ let handler = handler_clone.clone();
324
+ let hooks = hooks_clone.clone();
325
+ async move {
326
+ let (parts, body) = req.into_parts();
327
+ let request_data =
328
+ request_extraction::create_request_data_with_body(&parts, HashMap::new(), body).await?;
329
+ let mut req = Request::from_parts(
330
+ parts,
331
+ Body::from(request_data.raw_body.clone().unwrap_or_else(Bytes::new)),
332
+ );
333
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
334
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
335
+ .await
336
+ }
337
+ })
338
+ }
339
+ HttpMethod::Patch => {
340
+ let handler_clone = handler_clone.clone();
341
+ let hooks_clone = hooks_clone.clone();
342
+ axum::routing::patch(move |req: AxumRequest| {
343
+ let handler = handler_clone.clone();
344
+ let hooks = hooks_clone.clone();
345
+ async move {
346
+ let (parts, body) = req.into_parts();
347
+ let request_data =
348
+ request_extraction::create_request_data_with_body(&parts, HashMap::new(), body).await?;
349
+ let mut req = Request::from_parts(
350
+ parts,
351
+ Body::from(request_data.raw_body.clone().unwrap_or_else(Bytes::new)),
352
+ );
353
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
354
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
355
+ .await
356
+ }
357
+ })
358
+ }
359
+ _ => MethodRouter::new(),
360
+ }
361
+ } else {
362
+ match method {
363
+ HttpMethod::Get => {
364
+ let handler_clone = handler_clone.clone();
365
+ let hooks_clone = hooks_clone.clone();
366
+ axum::routing::get(move |req: AxumRequest| {
367
+ let handler = handler_clone.clone();
368
+ let hooks = hooks_clone.clone();
369
+ async move {
370
+ let request_data = request_extraction::create_request_data_without_body(
371
+ req.uri(),
372
+ req.method(),
373
+ req.headers(),
374
+ HashMap::new(),
375
+ );
376
+ let mut req = req;
377
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
378
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
379
+ .await
380
+ }
381
+ })
382
+ }
383
+ HttpMethod::Delete => {
384
+ let handler_clone = handler_clone.clone();
385
+ let hooks_clone = hooks_clone.clone();
386
+ axum::routing::delete(move |req: AxumRequest| {
387
+ let handler = handler_clone.clone();
388
+ let hooks = hooks_clone.clone();
389
+ async move {
390
+ let request_data = request_extraction::create_request_data_without_body(
391
+ req.uri(),
392
+ req.method(),
393
+ req.headers(),
394
+ HashMap::new(),
395
+ );
396
+ let mut req = req;
397
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
398
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
399
+ .await
400
+ }
401
+ })
402
+ }
403
+ HttpMethod::Head => {
404
+ let handler_clone = handler_clone.clone();
405
+ let hooks_clone = hooks_clone.clone();
406
+ axum::routing::head(move |req: AxumRequest| {
407
+ let handler = handler_clone.clone();
408
+ let hooks = hooks_clone.clone();
409
+ async move {
410
+ let request_data = request_extraction::create_request_data_without_body(
411
+ req.uri(),
412
+ req.method(),
413
+ req.headers(),
414
+ HashMap::new(),
415
+ );
416
+ let mut req = req;
417
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
418
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
419
+ .await
420
+ }
421
+ })
422
+ }
423
+ HttpMethod::Trace => {
424
+ let handler_clone = handler_clone.clone();
425
+ let hooks_clone = hooks_clone.clone();
426
+ axum::routing::trace(move |req: AxumRequest| {
427
+ let handler = handler_clone.clone();
428
+ let hooks = hooks_clone.clone();
429
+ async move {
430
+ let request_data = request_extraction::create_request_data_without_body(
431
+ req.uri(),
432
+ req.method(),
433
+ req.headers(),
434
+ HashMap::new(),
435
+ );
436
+ let mut req = req;
437
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
438
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
439
+ .await
440
+ }
441
+ })
442
+ }
443
+ HttpMethod::Options => {
444
+ let handler_clone = handler_clone.clone();
445
+ let hooks_clone = hooks_clone.clone();
446
+ axum::routing::options(move |req: AxumRequest| {
447
+ let handler = handler_clone.clone();
448
+ let hooks = hooks_clone.clone();
449
+ async move {
450
+ let request_data = request_extraction::create_request_data_without_body(
451
+ req.uri(),
452
+ req.method(),
453
+ req.headers(),
454
+ HashMap::new(),
455
+ );
456
+ let mut req = req;
457
+ req.extensions_mut().insert(Arc::new(request_data.clone()));
458
+ lifecycle_execution::execute_with_lifecycle_hooks(req, request_data, handler, hooks)
459
+ .await
460
+ }
461
+ })
462
+ }
463
+ _ => MethodRouter::new(),
464
+ }
465
+ }
466
+ }
467
+ }
468
+
469
+ #[cfg(test)]
470
+ mod tests {
471
+ use super::*;
472
+
473
+ #[test]
474
+ fn test_http_method_from_str() {
475
+ assert_eq!(HttpMethod::from_str("GET"), Some(HttpMethod::Get));
476
+ assert_eq!(HttpMethod::from_str("POST"), Some(HttpMethod::Post));
477
+ assert_eq!(HttpMethod::from_str("PUT"), Some(HttpMethod::Put));
478
+ assert_eq!(HttpMethod::from_str("PATCH"), Some(HttpMethod::Patch));
479
+ assert_eq!(HttpMethod::from_str("DELETE"), Some(HttpMethod::Delete));
480
+ assert_eq!(HttpMethod::from_str("HEAD"), Some(HttpMethod::Head));
481
+ assert_eq!(HttpMethod::from_str("TRACE"), Some(HttpMethod::Trace));
482
+ assert_eq!(HttpMethod::from_str("OPTIONS"), Some(HttpMethod::Options));
483
+ assert_eq!(HttpMethod::from_str("INVALID"), None);
484
+ }
485
+
486
+ #[test]
487
+ fn test_http_method_expects_body() {
488
+ assert!(!HttpMethod::Get.expects_body());
489
+ assert!(HttpMethod::Post.expects_body());
490
+ assert!(HttpMethod::Put.expects_body());
491
+ assert!(HttpMethod::Patch.expects_body());
492
+ assert!(!HttpMethod::Delete.expects_body());
493
+ assert!(!HttpMethod::Head.expects_body());
494
+ assert!(!HttpMethod::Trace.expects_body());
495
+ assert!(!HttpMethod::Options.expects_body());
496
+ }
497
+ }