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.
- checksums.yaml +7 -0
- data/LICENSE +1 -0
- data/README.md +659 -0
- data/ext/spikard_rb/Cargo.toml +17 -0
- data/ext/spikard_rb/extconf.rb +10 -0
- data/ext/spikard_rb/src/lib.rs +6 -0
- data/lib/spikard/app.rb +405 -0
- data/lib/spikard/background.rb +27 -0
- data/lib/spikard/config.rb +396 -0
- data/lib/spikard/converters.rb +13 -0
- data/lib/spikard/handler_wrapper.rb +113 -0
- data/lib/spikard/provide.rb +214 -0
- data/lib/spikard/response.rb +173 -0
- data/lib/spikard/schema.rb +243 -0
- data/lib/spikard/sse.rb +111 -0
- data/lib/spikard/streaming_response.rb +44 -0
- data/lib/spikard/testing.rb +221 -0
- data/lib/spikard/upload_file.rb +131 -0
- data/lib/spikard/version.rb +5 -0
- data/lib/spikard/websocket.rb +59 -0
- data/lib/spikard.rb +43 -0
- data/sig/spikard.rbs +366 -0
- data/vendor/bundle/ruby/3.4.0/gems/diff-lcs-1.6.2/mise.toml +5 -0
- data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.10.0/build/buildkitd.toml +2 -0
- data/vendor/crates/spikard-bindings-shared/Cargo.toml +63 -0
- data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +139 -0
- data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +561 -0
- data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +194 -0
- data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +246 -0
- data/vendor/crates/spikard-bindings-shared/src/error_response.rs +403 -0
- data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +274 -0
- data/vendor/crates/spikard-bindings-shared/src/lib.rs +25 -0
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +298 -0
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +637 -0
- data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +309 -0
- data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +248 -0
- data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +355 -0
- data/vendor/crates/spikard-bindings-shared/tests/comprehensive_coverage.rs +502 -0
- data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +389 -0
- data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +413 -0
- data/vendor/crates/spikard-core/Cargo.toml +40 -0
- data/vendor/crates/spikard-core/src/bindings/mod.rs +3 -0
- data/vendor/crates/spikard-core/src/bindings/response.rs +133 -0
- data/vendor/crates/spikard-core/src/debug.rs +63 -0
- data/vendor/crates/spikard-core/src/di/container.rs +726 -0
- data/vendor/crates/spikard-core/src/di/dependency.rs +273 -0
- data/vendor/crates/spikard-core/src/di/error.rs +118 -0
- data/vendor/crates/spikard-core/src/di/factory.rs +538 -0
- data/vendor/crates/spikard-core/src/di/graph.rs +545 -0
- data/vendor/crates/spikard-core/src/di/mod.rs +192 -0
- data/vendor/crates/spikard-core/src/di/resolved.rs +411 -0
- data/vendor/crates/spikard-core/src/di/value.rs +283 -0
- data/vendor/crates/spikard-core/src/errors.rs +39 -0
- data/vendor/crates/spikard-core/src/http.rs +153 -0
- data/vendor/crates/spikard-core/src/lib.rs +29 -0
- data/vendor/crates/spikard-core/src/lifecycle.rs +422 -0
- data/vendor/crates/spikard-core/src/metadata.rs +397 -0
- data/vendor/crates/spikard-core/src/parameters.rs +723 -0
- data/vendor/crates/spikard-core/src/problem.rs +310 -0
- data/vendor/crates/spikard-core/src/request_data.rs +189 -0
- data/vendor/crates/spikard-core/src/router.rs +249 -0
- data/vendor/crates/spikard-core/src/schema_registry.rs +183 -0
- data/vendor/crates/spikard-core/src/type_hints.rs +304 -0
- data/vendor/crates/spikard-core/src/validation/error_mapper.rs +689 -0
- data/vendor/crates/spikard-core/src/validation/mod.rs +459 -0
- data/vendor/crates/spikard-http/Cargo.toml +58 -0
- data/vendor/crates/spikard-http/examples/sse-notifications.rs +147 -0
- data/vendor/crates/spikard-http/examples/websocket-chat.rs +91 -0
- data/vendor/crates/spikard-http/src/auth.rs +247 -0
- data/vendor/crates/spikard-http/src/background.rs +1562 -0
- data/vendor/crates/spikard-http/src/bindings/mod.rs +3 -0
- data/vendor/crates/spikard-http/src/bindings/response.rs +1 -0
- data/vendor/crates/spikard-http/src/body_metadata.rs +8 -0
- data/vendor/crates/spikard-http/src/cors.rs +490 -0
- data/vendor/crates/spikard-http/src/debug.rs +63 -0
- data/vendor/crates/spikard-http/src/di_handler.rs +1878 -0
- data/vendor/crates/spikard-http/src/handler_response.rs +532 -0
- data/vendor/crates/spikard-http/src/handler_trait.rs +861 -0
- data/vendor/crates/spikard-http/src/handler_trait_tests.rs +284 -0
- data/vendor/crates/spikard-http/src/lib.rs +524 -0
- data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +149 -0
- data/vendor/crates/spikard-http/src/lifecycle.rs +428 -0
- data/vendor/crates/spikard-http/src/middleware/mod.rs +285 -0
- data/vendor/crates/spikard-http/src/middleware/multipart.rs +930 -0
- data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +541 -0
- data/vendor/crates/spikard-http/src/middleware/validation.rs +287 -0
- data/vendor/crates/spikard-http/src/openapi/mod.rs +309 -0
- data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +535 -0
- data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +867 -0
- data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +678 -0
- data/vendor/crates/spikard-http/src/query_parser.rs +369 -0
- data/vendor/crates/spikard-http/src/response.rs +399 -0
- data/vendor/crates/spikard-http/src/server/handler.rs +1557 -0
- data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +98 -0
- data/vendor/crates/spikard-http/src/server/mod.rs +806 -0
- data/vendor/crates/spikard-http/src/server/request_extraction.rs +630 -0
- data/vendor/crates/spikard-http/src/server/routing_factory.rs +497 -0
- data/vendor/crates/spikard-http/src/sse.rs +961 -0
- data/vendor/crates/spikard-http/src/testing/form.rs +14 -0
- data/vendor/crates/spikard-http/src/testing/multipart.rs +60 -0
- data/vendor/crates/spikard-http/src/testing/test_client.rs +285 -0
- data/vendor/crates/spikard-http/src/testing.rs +377 -0
- data/vendor/crates/spikard-http/src/websocket.rs +831 -0
- data/vendor/crates/spikard-http/tests/background_behavior.rs +918 -0
- data/vendor/crates/spikard-http/tests/common/handlers.rs +308 -0
- data/vendor/crates/spikard-http/tests/common/mod.rs +21 -0
- data/vendor/crates/spikard-http/tests/di_integration.rs +202 -0
- data/vendor/crates/spikard-http/tests/doc_snippets.rs +4 -0
- data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +1135 -0
- data/vendor/crates/spikard-http/tests/multipart_behavior.rs +688 -0
- data/vendor/crates/spikard-http/tests/server_config_builder.rs +324 -0
- data/vendor/crates/spikard-http/tests/sse_behavior.rs +728 -0
- data/vendor/crates/spikard-http/tests/websocket_behavior.rs +724 -0
- data/vendor/crates/spikard-rb/Cargo.toml +43 -0
- data/vendor/crates/spikard-rb/build.rs +199 -0
- data/vendor/crates/spikard-rb/src/background.rs +63 -0
- data/vendor/crates/spikard-rb/src/config/mod.rs +5 -0
- data/vendor/crates/spikard-rb/src/config/server_config.rs +283 -0
- data/vendor/crates/spikard-rb/src/conversion.rs +459 -0
- data/vendor/crates/spikard-rb/src/di/builder.rs +105 -0
- data/vendor/crates/spikard-rb/src/di/mod.rs +413 -0
- data/vendor/crates/spikard-rb/src/handler.rs +612 -0
- data/vendor/crates/spikard-rb/src/integration/mod.rs +3 -0
- data/vendor/crates/spikard-rb/src/lib.rs +1857 -0
- data/vendor/crates/spikard-rb/src/lifecycle.rs +275 -0
- data/vendor/crates/spikard-rb/src/metadata/mod.rs +5 -0
- data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +427 -0
- data/vendor/crates/spikard-rb/src/runtime/mod.rs +5 -0
- data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +326 -0
- data/vendor/crates/spikard-rb/src/server.rs +283 -0
- data/vendor/crates/spikard-rb/src/sse.rs +231 -0
- data/vendor/crates/spikard-rb/src/testing/client.rs +404 -0
- data/vendor/crates/spikard-rb/src/testing/mod.rs +7 -0
- data/vendor/crates/spikard-rb/src/testing/sse.rs +143 -0
- data/vendor/crates/spikard-rb/src/testing/websocket.rs +221 -0
- data/vendor/crates/spikard-rb/src/websocket.rs +233 -0
- data/vendor/crates/spikard-rb/tests/magnus_ffi_tests.rs +14 -0
- 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
|
+
}
|