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}