pavex/blueprint/wrapping.rs
1use super::reflection::AnnotationCoordinates;
2use crate::blueprint::ErrorHandler;
3use crate::blueprint::conversions::coordinates2coordinates;
4use pavex_bp_schema::{Blueprint as BlueprintSchema, Component, Location};
5
6/// The input type for [`Blueprint::wrap`].
7///
8/// Check out [`Blueprint::wrap`] for more information on wrapping middlewares
9/// in Pavex.
10///
11/// # Stability guarantees
12///
13/// Use the [`wrap`](macro@crate::wrap) attribute macro to create instances of `WrappingMiddleware`.\
14/// `WrappingMiddleware`'s fields are an implementation detail of Pavex's macros and should not be relied upon:
15/// newer versions of Pavex may add, remove or modify its fields.
16///
17/// [`Blueprint::wrap`]: crate::Blueprint::wrap
18pub struct WrappingMiddleware {
19 #[doc(hidden)]
20 pub coordinates: AnnotationCoordinates,
21}
22
23/// The type returned by [`Blueprint::wrap`].
24///
25/// It allows you to further configure the behaviour of the registered wrapping
26/// middleware.
27///
28/// [`Blueprint::wrap`]: crate::Blueprint::wrap
29pub struct RegisteredWrappingMiddleware<'a> {
30 pub(crate) blueprint: &'a mut BlueprintSchema,
31 /// The index of the registered middleware in the blueprint's `components` vector.
32 pub(crate) component_id: usize,
33}
34
35impl RegisteredWrappingMiddleware<'_> {
36 #[track_caller]
37 /// Register an error handler.
38 ///
39 /// If an error handler has already been registered for this middleware, it will be
40 /// overwritten.
41 ///
42 /// # Guide
43 ///
44 /// Check out the ["Error handlers"](https://pavex.dev/docs/guide/errors/error_handlers)
45 /// section of Pavex's guide for a thorough introduction to error handlers
46 /// in Pavex applications.
47 ///
48 /// # Example
49 ///
50 /// ```rust
51 /// use pavex::Blueprint;
52 /// use pavex::{error_handler, wrap, middleware::Next};
53 /// use pavex::Response;
54 /// use std::future::Future;
55 /// # struct LogLevel;
56 /// # struct Logger;
57 /// # struct TimeoutError;
58 ///
59 /// // 👇 a fallible middleware
60 /// #[wrap]
61 /// pub fn timeout_middleware<C>(next: Next<C>) -> Result<Response, TimeoutError>
62 /// where
63 /// C: Future<Output = Response>
64 /// {
65 /// // [...]
66 /// # todo!()
67 /// }
68 ///
69 /// #[error_handler]
70 /// pub fn timeout_error_handler(
71 /// #[px(error_ref)] error: &TimeoutError,
72 /// log_level: LogLevel
73 /// ) -> Response {
74 /// // [...]
75 /// # todo!()
76 /// }
77 ///
78 /// # fn main() {
79 /// let mut bp = Blueprint::new();
80 /// bp.wrap(TIMEOUT_MIDDLEWARE)
81 /// .error_handler(TIMEOUT_ERROR_HANDLER);
82 /// # }
83 /// ```
84 pub fn error_handler(mut self, error_handler: ErrorHandler) -> Self {
85 let error_handler = pavex_bp_schema::ErrorHandler {
86 coordinates: coordinates2coordinates(error_handler.coordinates),
87 registered_at: Location::caller(),
88 };
89 self.wrapping_middleware().error_handler = Some(error_handler);
90 self
91 }
92
93 fn wrapping_middleware(&mut self) -> &mut pavex_bp_schema::WrappingMiddleware {
94 let component = &mut self.blueprint.components[self.component_id];
95 let Component::WrappingMiddleware(c) = component else {
96 unreachable!("The component should be a wrapping middleware")
97 };
98 c
99 }
100}