volo_http/server/route/
mod.rs

1//! Route module for routing path to [`Service`]s or handlers.
2//!
3//! This module includes [`Router`], [`MethodRouter`] and [`Route`]. The call path is:
4//!
5//! `Router` -> `MethodRouter` -> `Route`.
6//!
7//! [`Router`] is the main router for routing path (uri) to [`MethodRouter`]s. [`MethodRouter`] is
8//! a router for routing method (GET, POST, ...) to [`Route`]s. [`Route`] is a handler or service
9//! for handling the request.
10
11use std::{convert::Infallible, future::Future, marker::PhantomData};
12
13use http::status::StatusCode;
14use motore::{ServiceExt, layer::Layer, service::Service};
15
16use super::{IntoResponse, handler::Handler};
17use crate::{body::Body, context::ServerContext, request::Request, response::Response};
18
19pub mod method_router;
20pub mod router;
21mod utils;
22
23pub use self::{method_router::*, router::Router};
24
25/// The route service used for [`Router`].
26pub struct Route<B = Body, E = Infallible> {
27    inner: motore::service::BoxService<ServerContext, Request<B>, Response, E>,
28}
29
30impl<B, E> Route<B, E> {
31    /// Create a new [`Route`] from a [`Service`].
32    pub fn new<S>(inner: S) -> Self
33    where
34        S: Service<ServerContext, Request<B>, Response = Response, Error = E>
35            + Send
36            + Sync
37            + 'static,
38        B: 'static,
39    {
40        Self {
41            inner: motore::service::BoxService::new(inner),
42        }
43    }
44}
45
46impl<B, E> Service<ServerContext, Request<B>> for Route<B, E> {
47    type Response = Response;
48    type Error = E;
49
50    fn call(
51        &self,
52        cx: &mut ServerContext,
53        req: Request<B>,
54    ) -> impl Future<Output = Result<Self::Response, Self::Error>> + Send {
55        self.inner.call(cx, req)
56    }
57}
58
59enum Fallback<B = Body, E = Infallible> {
60    Route(Route<B, E>),
61}
62
63impl<B, E> Service<ServerContext, Request<B>> for Fallback<B, E>
64where
65    B: Send,
66{
67    type Response = Response;
68    type Error = E;
69
70    async fn call(
71        &self,
72        cx: &mut ServerContext,
73        req: Request<B>,
74    ) -> Result<Self::Response, Self::Error> {
75        match self {
76            Self::Route(route) => route.call(cx, req).await,
77        }
78    }
79}
80
81impl<B, E> Fallback<B, E>
82where
83    B: Send + 'static,
84    E: 'static,
85{
86    fn from_status_code(status: StatusCode) -> Self {
87        Self::from_service(RouteForStatusCode::new(status))
88    }
89
90    fn from_handler<H, T>(handler: H) -> Self
91    where
92        H: Handler<T, B, E> + Clone + Send + Sync + 'static,
93        T: 'static,
94    {
95        Self::from_service(handler.into_service())
96    }
97
98    fn from_service<S>(service: S) -> Self
99    where
100        S: Service<ServerContext, Request<B>, Error = E> + Send + Sync + 'static,
101        S::Response: IntoResponse,
102    {
103        Self::Route(Route::new(
104            service.map_response(IntoResponse::into_response),
105        ))
106    }
107
108    fn map<F, B2, E2>(self, f: F) -> Fallback<B2, E2>
109    where
110        F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + 'static,
111    {
112        match self {
113            Self::Route(route) => Fallback::Route(f(route)),
114        }
115    }
116
117    fn layer<L, B2, E2>(self, l: L) -> Fallback<B2, E2>
118    where
119        L: Layer<Route<B, E>> + Clone + Send + Sync + 'static,
120        L::Service: Service<ServerContext, Request<B2>, Error = E2> + Send + Sync + 'static,
121        <L::Service as Service<ServerContext, Request<B2>>>::Response: IntoResponse,
122        B2: 'static,
123    {
124        self.map(move |route: Route<B, E>| {
125            Route::new(
126                l.clone()
127                    .layer(route)
128                    .map_response(IntoResponse::into_response),
129            )
130        })
131    }
132}
133
134struct RouteForStatusCode<B, E> {
135    status: StatusCode,
136    _marker: PhantomData<fn(B, E)>,
137}
138
139impl<B, E> Clone for RouteForStatusCode<B, E> {
140    fn clone(&self) -> Self {
141        Self {
142            status: self.status,
143            _marker: self._marker,
144        }
145    }
146}
147
148impl<B, E> RouteForStatusCode<B, E> {
149    fn new(status: StatusCode) -> Self {
150        Self {
151            status,
152            _marker: PhantomData,
153        }
154    }
155}
156
157impl<B, E> Service<ServerContext, Request<B>> for RouteForStatusCode<B, E>
158where
159    B: Send,
160{
161    type Response = Response;
162    type Error = E;
163
164    async fn call(
165        &self,
166        _: &mut ServerContext,
167        _: Request<B>,
168    ) -> Result<Self::Response, Self::Error> {
169        Ok(self.status.into_response())
170    }
171}