spikard 0.3.2 → 0.3.3
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 +4 -4
- data/LICENSE +1 -1
- data/README.md +659 -659
- data/ext/spikard_rb/Cargo.toml +17 -17
- data/ext/spikard_rb/extconf.rb +10 -10
- data/ext/spikard_rb/src/lib.rs +6 -6
- data/lib/spikard/app.rb +386 -386
- data/lib/spikard/background.rb +27 -27
- data/lib/spikard/config.rb +396 -396
- data/lib/spikard/converters.rb +13 -13
- data/lib/spikard/handler_wrapper.rb +113 -113
- data/lib/spikard/provide.rb +214 -214
- data/lib/spikard/response.rb +173 -173
- data/lib/spikard/schema.rb +243 -243
- data/lib/spikard/sse.rb +111 -111
- data/lib/spikard/streaming_response.rb +44 -44
- data/lib/spikard/testing.rb +221 -221
- data/lib/spikard/upload_file.rb +131 -131
- data/lib/spikard/version.rb +5 -5
- data/lib/spikard/websocket.rb +59 -59
- data/lib/spikard.rb +43 -43
- data/sig/spikard.rbs +360 -360
- data/vendor/crates/spikard-core/Cargo.toml +40 -40
- data/vendor/crates/spikard-core/src/bindings/mod.rs +3 -3
- data/vendor/crates/spikard-core/src/bindings/response.rs +133 -133
- data/vendor/crates/spikard-core/src/debug.rs +63 -63
- data/vendor/crates/spikard-core/src/di/container.rs +726 -726
- data/vendor/crates/spikard-core/src/di/dependency.rs +273 -273
- data/vendor/crates/spikard-core/src/di/error.rs +118 -118
- data/vendor/crates/spikard-core/src/di/factory.rs +538 -538
- data/vendor/crates/spikard-core/src/di/graph.rs +545 -545
- data/vendor/crates/spikard-core/src/di/mod.rs +192 -192
- data/vendor/crates/spikard-core/src/di/resolved.rs +411 -411
- data/vendor/crates/spikard-core/src/di/value.rs +283 -283
- data/vendor/crates/spikard-core/src/errors.rs +39 -39
- data/vendor/crates/spikard-core/src/http.rs +153 -153
- data/vendor/crates/spikard-core/src/lib.rs +29 -29
- data/vendor/crates/spikard-core/src/lifecycle.rs +422 -422
- data/vendor/crates/spikard-core/src/parameters.rs +722 -722
- data/vendor/crates/spikard-core/src/problem.rs +310 -310
- data/vendor/crates/spikard-core/src/request_data.rs +189 -189
- data/vendor/crates/spikard-core/src/router.rs +249 -249
- data/vendor/crates/spikard-core/src/schema_registry.rs +183 -183
- data/vendor/crates/spikard-core/src/type_hints.rs +304 -304
- data/vendor/crates/spikard-core/src/validation.rs +699 -699
- data/vendor/crates/spikard-http/Cargo.toml +58 -58
- data/vendor/crates/spikard-http/src/auth.rs +247 -247
- data/vendor/crates/spikard-http/src/background.rs +249 -249
- data/vendor/crates/spikard-http/src/bindings/mod.rs +3 -3
- data/vendor/crates/spikard-http/src/bindings/response.rs +1 -1
- data/vendor/crates/spikard-http/src/body_metadata.rs +8 -8
- data/vendor/crates/spikard-http/src/cors.rs +490 -490
- data/vendor/crates/spikard-http/src/debug.rs +63 -63
- data/vendor/crates/spikard-http/src/di_handler.rs +423 -423
- data/vendor/crates/spikard-http/src/handler_response.rs +190 -190
- data/vendor/crates/spikard-http/src/handler_trait.rs +228 -228
- data/vendor/crates/spikard-http/src/handler_trait_tests.rs +284 -284
- data/vendor/crates/spikard-http/src/lib.rs +529 -529
- data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +149 -149
- data/vendor/crates/spikard-http/src/lifecycle.rs +428 -428
- data/vendor/crates/spikard-http/src/middleware/mod.rs +285 -285
- data/vendor/crates/spikard-http/src/middleware/multipart.rs +86 -86
- data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +147 -147
- data/vendor/crates/spikard-http/src/middleware/validation.rs +287 -287
- data/vendor/crates/spikard-http/src/openapi/mod.rs +309 -309
- data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +190 -190
- data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +308 -308
- data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +195 -195
- data/vendor/crates/spikard-http/src/parameters.rs +1 -1
- data/vendor/crates/spikard-http/src/problem.rs +1 -1
- data/vendor/crates/spikard-http/src/query_parser.rs +369 -369
- data/vendor/crates/spikard-http/src/response.rs +399 -399
- data/vendor/crates/spikard-http/src/router.rs +1 -1
- data/vendor/crates/spikard-http/src/schema_registry.rs +1 -1
- data/vendor/crates/spikard-http/src/server/handler.rs +87 -87
- data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +98 -98
- data/vendor/crates/spikard-http/src/server/mod.rs +805 -805
- data/vendor/crates/spikard-http/src/server/request_extraction.rs +119 -119
- data/vendor/crates/spikard-http/src/sse.rs +447 -447
- data/vendor/crates/spikard-http/src/testing/form.rs +14 -14
- data/vendor/crates/spikard-http/src/testing/multipart.rs +60 -60
- data/vendor/crates/spikard-http/src/testing/test_client.rs +285 -285
- data/vendor/crates/spikard-http/src/testing.rs +377 -377
- data/vendor/crates/spikard-http/src/type_hints.rs +1 -1
- data/vendor/crates/spikard-http/src/validation.rs +1 -1
- data/vendor/crates/spikard-http/src/websocket.rs +324 -324
- data/vendor/crates/spikard-rb/Cargo.toml +42 -42
- data/vendor/crates/spikard-rb/build.rs +8 -8
- data/vendor/crates/spikard-rb/src/background.rs +63 -63
- data/vendor/crates/spikard-rb/src/config.rs +294 -294
- data/vendor/crates/spikard-rb/src/conversion.rs +453 -453
- data/vendor/crates/spikard-rb/src/di.rs +409 -409
- data/vendor/crates/spikard-rb/src/handler.rs +625 -625
- data/vendor/crates/spikard-rb/src/lib.rs +2771 -2771
- data/vendor/crates/spikard-rb/src/lifecycle.rs +274 -274
- data/vendor/crates/spikard-rb/src/server.rs +283 -283
- data/vendor/crates/spikard-rb/src/sse.rs +231 -231
- data/vendor/crates/spikard-rb/src/test_client.rs +404 -404
- data/vendor/crates/spikard-rb/src/test_sse.rs +143 -143
- data/vendor/crates/spikard-rb/src/test_websocket.rs +221 -221
- data/vendor/crates/spikard-rb/src/websocket.rs +233 -233
- data/vendor/spikard-core/Cargo.toml +40 -40
- data/vendor/spikard-core/src/bindings/mod.rs +3 -3
- data/vendor/spikard-core/src/bindings/response.rs +133 -133
- data/vendor/spikard-core/src/debug.rs +63 -63
- data/vendor/spikard-core/src/di/container.rs +726 -726
- data/vendor/spikard-core/src/di/dependency.rs +273 -273
- data/vendor/spikard-core/src/di/error.rs +118 -118
- data/vendor/spikard-core/src/di/factory.rs +538 -538
- data/vendor/spikard-core/src/di/graph.rs +545 -545
- data/vendor/spikard-core/src/di/mod.rs +192 -192
- data/vendor/spikard-core/src/di/resolved.rs +411 -411
- data/vendor/spikard-core/src/di/value.rs +283 -283
- data/vendor/spikard-core/src/http.rs +153 -153
- data/vendor/spikard-core/src/lib.rs +28 -28
- data/vendor/spikard-core/src/lifecycle.rs +422 -422
- data/vendor/spikard-core/src/parameters.rs +719 -719
- data/vendor/spikard-core/src/problem.rs +310 -310
- data/vendor/spikard-core/src/request_data.rs +189 -189
- data/vendor/spikard-core/src/router.rs +249 -249
- data/vendor/spikard-core/src/schema_registry.rs +183 -183
- data/vendor/spikard-core/src/type_hints.rs +304 -304
- data/vendor/spikard-core/src/validation.rs +699 -699
- data/vendor/spikard-http/Cargo.toml +58 -58
- data/vendor/spikard-http/src/auth.rs +247 -247
- data/vendor/spikard-http/src/background.rs +249 -249
- data/vendor/spikard-http/src/bindings/mod.rs +3 -3
- data/vendor/spikard-http/src/bindings/response.rs +1 -1
- data/vendor/spikard-http/src/body_metadata.rs +8 -8
- data/vendor/spikard-http/src/cors.rs +490 -490
- data/vendor/spikard-http/src/debug.rs +63 -63
- data/vendor/spikard-http/src/di_handler.rs +423 -423
- data/vendor/spikard-http/src/handler_response.rs +190 -190
- data/vendor/spikard-http/src/handler_trait.rs +228 -228
- data/vendor/spikard-http/src/handler_trait_tests.rs +284 -284
- data/vendor/spikard-http/src/lib.rs +529 -529
- data/vendor/spikard-http/src/lifecycle/adapter.rs +149 -149
- data/vendor/spikard-http/src/lifecycle.rs +428 -428
- data/vendor/spikard-http/src/middleware/mod.rs +285 -285
- data/vendor/spikard-http/src/middleware/multipart.rs +86 -86
- data/vendor/spikard-http/src/middleware/urlencoded.rs +147 -147
- data/vendor/spikard-http/src/middleware/validation.rs +287 -287
- data/vendor/spikard-http/src/openapi/mod.rs +309 -309
- data/vendor/spikard-http/src/openapi/parameter_extraction.rs +190 -190
- data/vendor/spikard-http/src/openapi/schema_conversion.rs +308 -308
- data/vendor/spikard-http/src/openapi/spec_generation.rs +195 -195
- data/vendor/spikard-http/src/parameters.rs +1 -1
- data/vendor/spikard-http/src/problem.rs +1 -1
- data/vendor/spikard-http/src/query_parser.rs +369 -369
- data/vendor/spikard-http/src/response.rs +399 -399
- data/vendor/spikard-http/src/router.rs +1 -1
- data/vendor/spikard-http/src/schema_registry.rs +1 -1
- data/vendor/spikard-http/src/server/handler.rs +80 -80
- data/vendor/spikard-http/src/server/lifecycle_execution.rs +98 -98
- data/vendor/spikard-http/src/server/mod.rs +805 -805
- data/vendor/spikard-http/src/server/request_extraction.rs +119 -119
- data/vendor/spikard-http/src/sse.rs +447 -447
- data/vendor/spikard-http/src/testing/form.rs +14 -14
- data/vendor/spikard-http/src/testing/multipart.rs +60 -60
- data/vendor/spikard-http/src/testing/test_client.rs +285 -285
- data/vendor/spikard-http/src/testing.rs +377 -377
- data/vendor/spikard-http/src/type_hints.rs +1 -1
- data/vendor/spikard-http/src/validation.rs +1 -1
- data/vendor/spikard-http/src/websocket.rs +324 -324
- data/vendor/spikard-rb/Cargo.toml +42 -42
- data/vendor/spikard-rb/build.rs +8 -8
- data/vendor/spikard-rb/src/background.rs +63 -63
- data/vendor/spikard-rb/src/config.rs +294 -294
- data/vendor/spikard-rb/src/conversion.rs +392 -392
- data/vendor/spikard-rb/src/di.rs +409 -409
- data/vendor/spikard-rb/src/handler.rs +534 -534
- data/vendor/spikard-rb/src/lib.rs +2020 -2020
- data/vendor/spikard-rb/src/lifecycle.rs +267 -267
- data/vendor/spikard-rb/src/server.rs +283 -283
- data/vendor/spikard-rb/src/sse.rs +231 -231
- data/vendor/spikard-rb/src/test_client.rs +404 -404
- data/vendor/spikard-rb/src/test_sse.rs +143 -143
- data/vendor/spikard-rb/src/test_websocket.rs +221 -221
- data/vendor/spikard-rb/src/websocket.rs +233 -233
- metadata +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
pub use spikard_core::router::*;
|
|
1
|
+
pub use spikard_core::router::*;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
pub use spikard_core::schema_registry::*;
|
|
1
|
+
pub use spikard_core::schema_registry::*;
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
//! ValidatingHandler wrapper that executes request/parameter validation before handler
|
|
2
|
-
|
|
3
|
-
use crate::ProblemDetails;
|
|
4
|
-
use crate::handler_trait::{Handler, HandlerResult, RequestData};
|
|
5
|
-
use crate::parameters::ParameterValidator;
|
|
6
|
-
use crate::validation::SchemaValidator;
|
|
7
|
-
use axum::body::Body;
|
|
8
|
-
use serde_json::Value;
|
|
9
|
-
use std::collections::HashMap;
|
|
10
|
-
use std::future::Future;
|
|
11
|
-
use std::pin::Pin;
|
|
12
|
-
use std::sync::Arc;
|
|
13
|
-
|
|
14
|
-
/// Wrapper that runs request/parameter validation before calling the user handler.
|
|
15
|
-
pub struct ValidatingHandler {
|
|
16
|
-
inner: Arc<dyn Handler>,
|
|
17
|
-
request_validator: Option<Arc<SchemaValidator>>,
|
|
18
|
-
parameter_validator: Option<ParameterValidator>,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
impl ValidatingHandler {
|
|
22
|
-
/// Create a new validating handler wrapping the inner handler with schema validators
|
|
23
|
-
pub fn new(inner: Arc<dyn Handler>, route: &crate::Route) -> Self {
|
|
24
|
-
Self {
|
|
25
|
-
inner,
|
|
26
|
-
request_validator: route.request_validator.clone(),
|
|
27
|
-
parameter_validator: route.parameter_validator.clone(),
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
impl Handler for ValidatingHandler {
|
|
33
|
-
fn call(
|
|
34
|
-
&self,
|
|
35
|
-
req: axum::http::Request<Body>,
|
|
36
|
-
mut request_data: RequestData,
|
|
37
|
-
) -> Pin<Box<dyn Future<Output = HandlerResult> + Send + '_>> {
|
|
38
|
-
let inner = self.inner.clone();
|
|
39
|
-
let request_validator = self.request_validator.clone();
|
|
40
|
-
let parameter_validator = self.parameter_validator.clone();
|
|
41
|
-
|
|
42
|
-
Box::pin(async move {
|
|
43
|
-
if let Some(validator) = request_validator {
|
|
44
|
-
if request_data.body.is_null() && request_data.raw_body.is_some() {
|
|
45
|
-
let raw_bytes = request_data.raw_body.as_ref().unwrap();
|
|
46
|
-
request_data.body = serde_json::from_slice::<Value>(raw_bytes)
|
|
47
|
-
.map_err(|e| (axum::http::StatusCode::BAD_REQUEST, format!("Invalid JSON: {}", e)))?;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if let Err(errors) = validator.validate(&request_data.body) {
|
|
51
|
-
let problem = ProblemDetails::from_validation_error(&errors);
|
|
52
|
-
let body = problem.to_json().unwrap_or_else(|_| "{}".to_string());
|
|
53
|
-
return Err((problem.status_code(), body));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if let Some(validator) = parameter_validator {
|
|
58
|
-
let raw_query_strings: HashMap<String, String> = request_data
|
|
59
|
-
.raw_query_params
|
|
60
|
-
.iter()
|
|
61
|
-
.filter_map(|(k, v)| v.first().map(|value| (k.clone(), value.clone())))
|
|
62
|
-
.collect();
|
|
63
|
-
|
|
64
|
-
if let Err(errors) = validator.validate_and_extract(
|
|
65
|
-
&request_data.query_params,
|
|
66
|
-
&raw_query_strings,
|
|
67
|
-
&request_data.path_params,
|
|
68
|
-
&request_data.headers,
|
|
69
|
-
&request_data.cookies,
|
|
70
|
-
) {
|
|
71
|
-
let problem = ProblemDetails::from_validation_error(&errors);
|
|
72
|
-
let body = problem.to_json().unwrap_or_else(|_| "{}".to_string());
|
|
73
|
-
return Err((problem.status_code(), body));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
inner.call(req, request_data).await
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
}
|
|
1
|
+
//! ValidatingHandler wrapper that executes request/parameter validation before handler
|
|
2
|
+
|
|
3
|
+
use crate::ProblemDetails;
|
|
4
|
+
use crate::handler_trait::{Handler, HandlerResult, RequestData};
|
|
5
|
+
use crate::parameters::ParameterValidator;
|
|
6
|
+
use crate::validation::SchemaValidator;
|
|
7
|
+
use axum::body::Body;
|
|
8
|
+
use serde_json::Value;
|
|
9
|
+
use std::collections::HashMap;
|
|
10
|
+
use std::future::Future;
|
|
11
|
+
use std::pin::Pin;
|
|
12
|
+
use std::sync::Arc;
|
|
13
|
+
|
|
14
|
+
/// Wrapper that runs request/parameter validation before calling the user handler.
|
|
15
|
+
pub struct ValidatingHandler {
|
|
16
|
+
inner: Arc<dyn Handler>,
|
|
17
|
+
request_validator: Option<Arc<SchemaValidator>>,
|
|
18
|
+
parameter_validator: Option<ParameterValidator>,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl ValidatingHandler {
|
|
22
|
+
/// Create a new validating handler wrapping the inner handler with schema validators
|
|
23
|
+
pub fn new(inner: Arc<dyn Handler>, route: &crate::Route) -> Self {
|
|
24
|
+
Self {
|
|
25
|
+
inner,
|
|
26
|
+
request_validator: route.request_validator.clone(),
|
|
27
|
+
parameter_validator: route.parameter_validator.clone(),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
impl Handler for ValidatingHandler {
|
|
33
|
+
fn call(
|
|
34
|
+
&self,
|
|
35
|
+
req: axum::http::Request<Body>,
|
|
36
|
+
mut request_data: RequestData,
|
|
37
|
+
) -> Pin<Box<dyn Future<Output = HandlerResult> + Send + '_>> {
|
|
38
|
+
let inner = self.inner.clone();
|
|
39
|
+
let request_validator = self.request_validator.clone();
|
|
40
|
+
let parameter_validator = self.parameter_validator.clone();
|
|
41
|
+
|
|
42
|
+
Box::pin(async move {
|
|
43
|
+
if let Some(validator) = request_validator {
|
|
44
|
+
if request_data.body.is_null() && request_data.raw_body.is_some() {
|
|
45
|
+
let raw_bytes = request_data.raw_body.as_ref().unwrap();
|
|
46
|
+
request_data.body = serde_json::from_slice::<Value>(raw_bytes)
|
|
47
|
+
.map_err(|e| (axum::http::StatusCode::BAD_REQUEST, format!("Invalid JSON: {}", e)))?;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if let Err(errors) = validator.validate(&request_data.body) {
|
|
51
|
+
let problem = ProblemDetails::from_validation_error(&errors);
|
|
52
|
+
let body = problem.to_json().unwrap_or_else(|_| "{}".to_string());
|
|
53
|
+
return Err((problem.status_code(), body));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if let Some(validator) = parameter_validator {
|
|
58
|
+
let raw_query_strings: HashMap<String, String> = request_data
|
|
59
|
+
.raw_query_params
|
|
60
|
+
.iter()
|
|
61
|
+
.filter_map(|(k, v)| v.first().map(|value| (k.clone(), value.clone())))
|
|
62
|
+
.collect();
|
|
63
|
+
|
|
64
|
+
if let Err(errors) = validator.validate_and_extract(
|
|
65
|
+
&request_data.query_params,
|
|
66
|
+
&raw_query_strings,
|
|
67
|
+
&request_data.path_params,
|
|
68
|
+
&request_data.headers,
|
|
69
|
+
&request_data.cookies,
|
|
70
|
+
) {
|
|
71
|
+
let problem = ProblemDetails::from_validation_error(&errors);
|
|
72
|
+
let body = problem.to_json().unwrap_or_else(|_| "{}".to_string());
|
|
73
|
+
return Err((problem.status_code(), body));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
inner.call(req, request_data).await
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
//! Lifecycle hooks execution logic
|
|
2
|
-
|
|
3
|
-
use crate::handler_trait::Handler;
|
|
4
|
-
use axum::body::Body;
|
|
5
|
-
use axum::http::StatusCode;
|
|
6
|
-
use std::sync::Arc;
|
|
7
|
-
|
|
8
|
-
/// Execute a handler with lifecycle hooks
|
|
9
|
-
///
|
|
10
|
-
/// This wraps the handler execution with lifecycle hooks at appropriate points:
|
|
11
|
-
/// 1. preValidation hooks (before handler, which does validation)
|
|
12
|
-
/// 2. preHandler hooks (after validation, before handler)
|
|
13
|
-
/// 3. Handler execution
|
|
14
|
-
/// 4. onResponse hooks (after successful handler execution)
|
|
15
|
-
/// 5. onError hooks (if handler or any hook fails)
|
|
16
|
-
pub async fn execute_with_lifecycle_hooks(
|
|
17
|
-
req: axum::http::Request<Body>,
|
|
18
|
-
request_data: crate::handler_trait::RequestData,
|
|
19
|
-
handler: Arc<dyn Handler>,
|
|
20
|
-
hooks: Option<Arc<crate::LifecycleHooks>>,
|
|
21
|
-
) -> Result<axum::http::Response<Body>, (axum::http::StatusCode, String)> {
|
|
22
|
-
use crate::lifecycle::HookResult;
|
|
23
|
-
|
|
24
|
-
let Some(hooks) = hooks else {
|
|
25
|
-
return handler.call(req, request_data).await;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
if hooks.is_empty() {
|
|
29
|
-
return handler.call(req, request_data).await;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
let req = match hooks.execute_pre_validation(req).await {
|
|
33
|
-
Ok(HookResult::Continue(r)) => r,
|
|
34
|
-
Ok(HookResult::ShortCircuit(response)) => return Ok(response),
|
|
35
|
-
Err(e) => {
|
|
36
|
-
let error_response = axum::http::Response::builder()
|
|
37
|
-
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
38
|
-
.body(Body::from(format!(
|
|
39
|
-
"{{\"error\":\"preValidation hook failed: {}\"}}",
|
|
40
|
-
e
|
|
41
|
-
)))
|
|
42
|
-
.unwrap();
|
|
43
|
-
|
|
44
|
-
return match hooks.execute_on_error(error_response).await {
|
|
45
|
-
Ok(resp) => Ok(resp),
|
|
46
|
-
Err(_) => Ok(axum::http::Response::builder()
|
|
47
|
-
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
48
|
-
.body(Body::from("{\"error\":\"Hook execution failed\"}"))
|
|
49
|
-
.unwrap()),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
let req = match hooks.execute_pre_handler(req).await {
|
|
55
|
-
Ok(HookResult::Continue(r)) => r,
|
|
56
|
-
Ok(HookResult::ShortCircuit(response)) => return Ok(response),
|
|
57
|
-
Err(e) => {
|
|
58
|
-
let error_response = axum::http::Response::builder()
|
|
59
|
-
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
60
|
-
.body(Body::from(format!("{{\"error\":\"preHandler hook failed: {}\"}}", e)))
|
|
61
|
-
.unwrap();
|
|
62
|
-
|
|
63
|
-
return match hooks.execute_on_error(error_response).await {
|
|
64
|
-
Ok(resp) => Ok(resp),
|
|
65
|
-
Err(_) => Ok(axum::http::Response::builder()
|
|
66
|
-
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
67
|
-
.body(Body::from("{\"error\":\"Hook execution failed\"}"))
|
|
68
|
-
.unwrap()),
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
let response = match handler.call(req, request_data).await {
|
|
74
|
-
Ok(resp) => resp,
|
|
75
|
-
Err((status, message)) => {
|
|
76
|
-
let error_response = axum::http::Response::builder()
|
|
77
|
-
.status(status)
|
|
78
|
-
.body(Body::from(message))
|
|
79
|
-
.unwrap();
|
|
80
|
-
|
|
81
|
-
return match hooks.execute_on_error(error_response).await {
|
|
82
|
-
Ok(resp) => Ok(resp),
|
|
83
|
-
Err(e) => Ok(axum::http::Response::builder()
|
|
84
|
-
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
85
|
-
.body(Body::from(format!("{{\"error\":\"onError hook failed: {}\"}}", e)))
|
|
86
|
-
.unwrap()),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
match hooks.execute_on_response(response).await {
|
|
92
|
-
Ok(resp) => Ok(resp),
|
|
93
|
-
Err(e) => Ok(axum::http::Response::builder()
|
|
94
|
-
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
95
|
-
.body(Body::from(format!("{{\"error\":\"onResponse hook failed: {}\"}}", e)))
|
|
96
|
-
.unwrap()),
|
|
97
|
-
}
|
|
98
|
-
}
|
|
1
|
+
//! Lifecycle hooks execution logic
|
|
2
|
+
|
|
3
|
+
use crate::handler_trait::Handler;
|
|
4
|
+
use axum::body::Body;
|
|
5
|
+
use axum::http::StatusCode;
|
|
6
|
+
use std::sync::Arc;
|
|
7
|
+
|
|
8
|
+
/// Execute a handler with lifecycle hooks
|
|
9
|
+
///
|
|
10
|
+
/// This wraps the handler execution with lifecycle hooks at appropriate points:
|
|
11
|
+
/// 1. preValidation hooks (before handler, which does validation)
|
|
12
|
+
/// 2. preHandler hooks (after validation, before handler)
|
|
13
|
+
/// 3. Handler execution
|
|
14
|
+
/// 4. onResponse hooks (after successful handler execution)
|
|
15
|
+
/// 5. onError hooks (if handler or any hook fails)
|
|
16
|
+
pub async fn execute_with_lifecycle_hooks(
|
|
17
|
+
req: axum::http::Request<Body>,
|
|
18
|
+
request_data: crate::handler_trait::RequestData,
|
|
19
|
+
handler: Arc<dyn Handler>,
|
|
20
|
+
hooks: Option<Arc<crate::LifecycleHooks>>,
|
|
21
|
+
) -> Result<axum::http::Response<Body>, (axum::http::StatusCode, String)> {
|
|
22
|
+
use crate::lifecycle::HookResult;
|
|
23
|
+
|
|
24
|
+
let Some(hooks) = hooks else {
|
|
25
|
+
return handler.call(req, request_data).await;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
if hooks.is_empty() {
|
|
29
|
+
return handler.call(req, request_data).await;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let req = match hooks.execute_pre_validation(req).await {
|
|
33
|
+
Ok(HookResult::Continue(r)) => r,
|
|
34
|
+
Ok(HookResult::ShortCircuit(response)) => return Ok(response),
|
|
35
|
+
Err(e) => {
|
|
36
|
+
let error_response = axum::http::Response::builder()
|
|
37
|
+
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
38
|
+
.body(Body::from(format!(
|
|
39
|
+
"{{\"error\":\"preValidation hook failed: {}\"}}",
|
|
40
|
+
e
|
|
41
|
+
)))
|
|
42
|
+
.unwrap();
|
|
43
|
+
|
|
44
|
+
return match hooks.execute_on_error(error_response).await {
|
|
45
|
+
Ok(resp) => Ok(resp),
|
|
46
|
+
Err(_) => Ok(axum::http::Response::builder()
|
|
47
|
+
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
48
|
+
.body(Body::from("{\"error\":\"Hook execution failed\"}"))
|
|
49
|
+
.unwrap()),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
let req = match hooks.execute_pre_handler(req).await {
|
|
55
|
+
Ok(HookResult::Continue(r)) => r,
|
|
56
|
+
Ok(HookResult::ShortCircuit(response)) => return Ok(response),
|
|
57
|
+
Err(e) => {
|
|
58
|
+
let error_response = axum::http::Response::builder()
|
|
59
|
+
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
60
|
+
.body(Body::from(format!("{{\"error\":\"preHandler hook failed: {}\"}}", e)))
|
|
61
|
+
.unwrap();
|
|
62
|
+
|
|
63
|
+
return match hooks.execute_on_error(error_response).await {
|
|
64
|
+
Ok(resp) => Ok(resp),
|
|
65
|
+
Err(_) => Ok(axum::http::Response::builder()
|
|
66
|
+
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
67
|
+
.body(Body::from("{\"error\":\"Hook execution failed\"}"))
|
|
68
|
+
.unwrap()),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
let response = match handler.call(req, request_data).await {
|
|
74
|
+
Ok(resp) => resp,
|
|
75
|
+
Err((status, message)) => {
|
|
76
|
+
let error_response = axum::http::Response::builder()
|
|
77
|
+
.status(status)
|
|
78
|
+
.body(Body::from(message))
|
|
79
|
+
.unwrap();
|
|
80
|
+
|
|
81
|
+
return match hooks.execute_on_error(error_response).await {
|
|
82
|
+
Ok(resp) => Ok(resp),
|
|
83
|
+
Err(e) => Ok(axum::http::Response::builder()
|
|
84
|
+
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
85
|
+
.body(Body::from(format!("{{\"error\":\"onError hook failed: {}\"}}", e)))
|
|
86
|
+
.unwrap()),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
match hooks.execute_on_response(response).await {
|
|
92
|
+
Ok(resp) => Ok(resp),
|
|
93
|
+
Err(e) => Ok(axum::http::Response::builder()
|
|
94
|
+
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
95
|
+
.body(Body::from(format!("{{\"error\":\"onResponse hook failed: {}\"}}", e)))
|
|
96
|
+
.unwrap()),
|
|
97
|
+
}
|
|
98
|
+
}
|