seamless/handler/
param.rs

1use http::{ Request };
2use async_trait::async_trait;
3use crate::api::ApiError;
4
5/// Implement this for anything that you want to be able to pass into a request
6/// handler that doesn't want to consume the body of the request. This is
7/// useful for implementing request guards which prevent the handler from being
8/// called unless specific conditions are met (for instance a user is logged
9/// in).
10///
11/// # Example
12///
13/// ```
14/// # use seamless::handler::HandlerParam;
15/// # use seamless::http::Request;
16/// # use seamless::api::ApiError;
17/// # struct State;
18/// # impl State {
19/// #     async fn get_user(&self, req: &Request<()>) -> Result<User,ApiError> {
20/// #         Ok(User { id: "Foo".to_owned() })
21/// #     }
22/// # }
23/// // This represents a valid user of the API.
24/// pub struct User { pub id: String }
25///
26/// // Make it possible to ask for the current user in a request:
27/// #[seamless::async_trait]
28/// impl HandlerParam for User {
29///     type Error = ApiError;
30///     async fn handler_param(req: &Request<()>) -> Result<Self,Self::Error> {
31///         // We can put things (like DB connections) into requests before they
32///         // are handed to the API, and then pluck them out here to use:
33///         let state = req.extensions()
34///             .get::<State>()
35///             .map(|s| s.clone())
36///             .unwrap();
37///         state.get_user(req).await
38///     }
39/// }
40/// ```
41#[async_trait]
42pub trait HandlerParam where Self: Sized {
43    /// An error indicating what went wrong in the event that we fail to extract
44    /// our parameter from the provided request.
45    ///
46    /// To be usable with [`crate::api::Api`], the error should implement `Into<ApiError>`
47    /// (the [`macro@crate::ApiError`] macro can be used to gelp with this).
48    ///
49    /// It can be simpler just to set this to `ApiError` directly.
50    type Error: Into<ApiError> + 'static;
51    /// Given a [`http::Request<()>`], return a value of type `T` back, or
52    /// else return an error of type `E` describing what went wrong. Any errors
53    /// here will lead to the route bailing out and the handler not being run.
54    async fn handler_param(req: &Request<()>) -> Result<Self,Self::Error>;
55}
56
57// Option<Body> means we'll return None to the handler if handler_param would fail.
58// This will never error.
59#[async_trait]
60impl <T: HandlerParam> HandlerParam for Option<T> {
61    type Error = std::convert::Infallible;
62    async fn handler_param(req: &Request<()>) -> Result<Self,Self::Error> {
63        Ok(T::handler_param(req).await.ok())
64    }
65}
66
67// Result<Context,Err> means we'll return the result of attempting to obtain the context.
68// This will never error.
69#[async_trait]
70impl <T: HandlerParam> HandlerParam for Result<T,<T as HandlerParam>::Error> {
71    type Error = <T as HandlerParam>::Error;
72    async fn handler_param(req: &Request<()>) -> Result<Self,Self::Error> {
73        Ok(T::handler_param(req).await)
74    }
75}