Skip to main content

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::{
24    method_router::*,
25    router::{MatchedPath, Router},
26};
27
28/// The route service used for [`Router`].
29pub struct Route<B = Body, E = Infallible> {
30    inner: motore::service::BoxService<ServerContext, Request<B>, Response, E>,
31}
32
33impl<B, E> Route<B, E> {
34    /// Create a new [`Route`] from a [`Service`].
35    pub fn new<S>(inner: S) -> Self
36    where
37        S: Service<ServerContext, Request<B>, Response = Response, Error = E>
38            + Send
39            + Sync
40            + 'static,
41        B: 'static,
42    {
43        Self {
44            inner: motore::service::BoxService::new(inner),
45        }
46    }
47}
48
49impl<B, E> Service<ServerContext, Request<B>> for Route<B, E> {
50    type Response = Response;
51    type Error = E;
52
53    fn call(
54        &self,
55        cx: &mut ServerContext,
56        req: Request<B>,
57    ) -> impl Future<Output = Result<Self::Response, Self::Error>> + Send {
58        self.inner.call(cx, req)
59    }
60}
61
62enum Fallback<B = Body, E = Infallible> {
63    Route(Route<B, E>),
64}
65
66impl<B, E> Service<ServerContext, Request<B>> for Fallback<B, E>
67where
68    B: Send,
69{
70    type Response = Response;
71    type Error = E;
72
73    async fn call(
74        &self,
75        cx: &mut ServerContext,
76        req: Request<B>,
77    ) -> Result<Self::Response, Self::Error> {
78        match self {
79            Self::Route(route) => route.call(cx, req).await,
80        }
81    }
82}
83
84impl<B, E> Fallback<B, E>
85where
86    B: Send + 'static,
87    E: 'static,
88{
89    fn from_status_code(status: StatusCode) -> Self {
90        Self::from_service(RouteForStatusCode::new(status))
91    }
92
93    fn from_handler<H, T>(handler: H) -> Self
94    where
95        H: Handler<T, B, E> + Clone + Send + Sync + 'static,
96        T: 'static,
97    {
98        Self::from_service(handler.into_service())
99    }
100
101    fn from_service<S>(service: S) -> Self
102    where
103        S: Service<ServerContext, Request<B>, Error = E> + Send + Sync + 'static,
104        S::Response: IntoResponse,
105    {
106        Self::Route(Route::new(
107            service.map_response(IntoResponse::into_response),
108        ))
109    }
110
111    fn map<F, B2, E2>(self, f: F) -> Fallback<B2, E2>
112    where
113        F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + 'static,
114    {
115        match self {
116            Self::Route(route) => Fallback::Route(f(route)),
117        }
118    }
119
120    fn layer<L, B2, E2>(self, l: L) -> Fallback<B2, E2>
121    where
122        L: Layer<Route<B, E>> + Clone + Send + Sync + 'static,
123        L::Service: Service<ServerContext, Request<B2>, Error = E2> + Send + Sync + 'static,
124        <L::Service as Service<ServerContext, Request<B2>>>::Response: IntoResponse,
125        B2: 'static,
126    {
127        self.map(move |route: Route<B, E>| {
128            Route::new(
129                l.clone()
130                    .layer(route)
131                    .map_response(IntoResponse::into_response),
132            )
133        })
134    }
135}
136
137struct RouteForStatusCode<B, E> {
138    status: StatusCode,
139    _marker: PhantomData<fn(B, E)>,
140}
141
142impl<B, E> Clone for RouteForStatusCode<B, E> {
143    fn clone(&self) -> Self {
144        Self {
145            status: self.status,
146            _marker: self._marker,
147        }
148    }
149}
150
151impl<B, E> RouteForStatusCode<B, E> {
152    fn new(status: StatusCode) -> Self {
153        Self {
154            status,
155            _marker: PhantomData,
156        }
157    }
158}
159
160impl<B, E> Service<ServerContext, Request<B>> for RouteForStatusCode<B, E>
161where
162    B: Send,
163{
164    type Response = Response;
165    type Error = E;
166
167    async fn call(
168        &self,
169        _: &mut ServerContext,
170        _: Request<B>,
171    ) -> Result<Self::Response, Self::Error> {
172        Ok(self.status.into_response())
173    }
174}