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}