dhttp/core/
service.rs

1use std::pin::Pin;
2
3use crate::reqres::{HttpRequest, HttpMethod, StatusCode};
4use crate::core::{HttpResult, HttpRead};
5
6/// Basic building block of your web application
7///
8/// Use it to implement the service, and use [`HttpServiceRaw`] to call it from a `&dyn` reference
9pub trait HttpService: Send + Sync + 'static {
10    /// Serve the request
11    ///
12    /// Equivalent signature:
13    /// `async fn request(&self, route: &str, req: &HttpRequest, body: &dyn HttpRead) -> HttpResult`
14    ///
15    /// The `route` argument contains the resolved route, while `req.route` contains the full original route.
16    /// Always use `route` instead of `req.route`!
17    fn request(&self, route: &str, req: &HttpRequest, body: &mut dyn HttpRead) -> impl Future<Output = HttpResult> + Send;
18
19    /// Checks if request is valid
20    ///
21    /// By default, it checks that route is `"/"`, method is [`HttpMethod::Get`] and `req.len` is 0
22    fn filter(&self, route: &str, req: &HttpRequest) -> HttpResult<()> {
23        if route != "/" { return Err(StatusCode::NOT_FOUND.into()); }
24        if req.method != HttpMethod::Get { return Err(StatusCode::METHOD_NOT_ALLOWED.into()); }
25        if req.len > 0 { return Err(StatusCode::REQUEST_ENTITY_TOO_LARGE.into()); }
26        Ok(())
27    }
28}
29
30/// Dyn version of [`HttpService`]
31///
32/// The raw version is required to overcome the ugliness of dyn Future signatures
33///
34/// Use it to call the service, and use [`HttpService`] to implement it.
35pub trait HttpServiceRaw: Send + Sync + 'static {
36    /// Serve the request (dyn version)
37    fn request_raw<'a>(&'a self, route: &'a str, req: &'a HttpRequest, body: &'a mut dyn HttpRead) -> Pin<Box<dyn Future<Output = HttpResult> + Send + 'a>>;
38    /// Checks if request is valid (dyn version)
39    fn filter_raw(&self, route: &str, req: &HttpRequest) -> HttpResult<()>;
40}
41
42impl<T: HttpService> HttpServiceRaw for T {
43    fn request_raw<'a>(&'a self, route: &'a str, req: &'a HttpRequest, body: &'a mut dyn HttpRead) -> Pin<Box<dyn Future<Output = HttpResult> + Send + 'a>> {
44        Box::pin(self.request(route, req, body))
45    }
46
47    fn filter_raw(&self, route: &str, req: &HttpRequest) -> HttpResult<()> {
48        self.filter(route, req)
49    }
50}