axum/routing/
mod.rs

1//! Routing between [`Service`]s and handlers.
2
3use self::{future::RouteFuture, not_found::NotFound, path_router::PathRouter};
4#[cfg(feature = "tokio")]
5use crate::extract::connect_info::IntoMakeServiceWithConnectInfo;
6use crate::{
7    body::{Body, HttpBody},
8    boxed::BoxedIntoRoute,
9    handler::Handler,
10    util::try_downcast,
11};
12use axum_core::{
13    extract::Request,
14    response::{IntoResponse, Response},
15};
16use std::{
17    convert::Infallible,
18    fmt,
19    marker::PhantomData,
20    sync::Arc,
21    task::{Context, Poll},
22};
23use tower_layer::Layer;
24use tower_service::Service;
25
26pub mod future;
27pub mod method_routing;
28
29mod into_make_service;
30mod method_filter;
31mod not_found;
32pub(crate) mod path_router;
33mod route;
34mod strip_prefix;
35pub(crate) mod url_params;
36
37#[cfg(test)]
38mod tests;
39
40pub use self::{into_make_service::IntoMakeService, method_filter::MethodFilter, route::Route};
41
42pub use self::method_routing::{
43    any, any_service, connect, connect_service, delete, delete_service, get, get_service, head,
44    head_service, on, on_service, options, options_service, patch, patch_service, post,
45    post_service, put, put_service, trace, trace_service, MethodRouter,
46};
47
48macro_rules! panic_on_err {
49    ($expr:expr) => {
50        match $expr {
51            Ok(x) => x,
52            Err(err) => panic!("{err}"),
53        }
54    };
55}
56
57#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
58pub(crate) struct RouteId(u32);
59
60/// The router type for composing handlers and services.
61#[must_use]
62pub struct Router<S = ()> {
63    inner: Arc<RouterInner<S>>,
64}
65
66impl<S> Clone for Router<S> {
67    fn clone(&self) -> Self {
68        Self {
69            inner: Arc::clone(&self.inner),
70        }
71    }
72}
73
74struct RouterInner<S> {
75    path_router: PathRouter<S, false>,
76    fallback_router: PathRouter<S, true>,
77    default_fallback: bool,
78    catch_all_fallback: Fallback<S>,
79}
80
81impl<S> Default for Router<S>
82where
83    S: Clone + Send + Sync + 'static,
84{
85    fn default() -> Self {
86        Self::new()
87    }
88}
89
90impl<S> fmt::Debug for Router<S> {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        f.debug_struct("Router")
93            .field("path_router", &self.inner.path_router)
94            .field("fallback_router", &self.inner.fallback_router)
95            .field("default_fallback", &self.inner.default_fallback)
96            .field("catch_all_fallback", &self.inner.catch_all_fallback)
97            .finish()
98    }
99}
100
101pub(crate) const NEST_TAIL_PARAM: &str = "__private__axum_nest_tail_param";
102#[cfg(feature = "matched-path")]
103pub(crate) const NEST_TAIL_PARAM_CAPTURE: &str = "/{*__private__axum_nest_tail_param}";
104pub(crate) const FALLBACK_PARAM: &str = "__private__axum_fallback";
105pub(crate) const FALLBACK_PARAM_PATH: &str = "/{*__private__axum_fallback}";
106
107macro_rules! map_inner {
108    ( $self_:ident, $inner:pat_param => $expr:expr) => {
109        #[allow(redundant_semicolons)]
110        {
111            let $inner = $self_.into_inner();
112            Router {
113                inner: Arc::new($expr),
114            }
115        }
116    };
117}
118
119macro_rules! tap_inner {
120    ( $self_:ident, mut $inner:ident => { $($stmt:stmt)* } ) => {
121        #[allow(redundant_semicolons)]
122        {
123            let mut $inner = $self_.into_inner();
124            $($stmt)*
125            Router {
126                inner: Arc::new($inner),
127            }
128        }
129    };
130}
131
132impl<S> Router<S>
133where
134    S: Clone + Send + Sync + 'static,
135{
136    /// Create a new `Router`.
137    ///
138    /// Unless you add additional routes this will respond with `404 Not Found` to
139    /// all requests.
140    pub fn new() -> Self {
141        Self {
142            inner: Arc::new(RouterInner {
143                path_router: Default::default(),
144                fallback_router: PathRouter::new_fallback(),
145                default_fallback: true,
146                catch_all_fallback: Fallback::Default(Route::new(NotFound)),
147            }),
148        }
149    }
150
151    fn into_inner(self) -> RouterInner<S> {
152        match Arc::try_unwrap(self.inner) {
153            Ok(inner) => inner,
154            Err(arc) => RouterInner {
155                path_router: arc.path_router.clone(),
156                fallback_router: arc.fallback_router.clone(),
157                default_fallback: arc.default_fallback,
158                catch_all_fallback: arc.catch_all_fallback.clone(),
159            },
160        }
161    }
162
163    #[doc = include_str!("../docs/routing/without_v07_checks.md")]
164    pub fn without_v07_checks(self) -> Self {
165        tap_inner!(self, mut this => {
166            this.path_router.without_v07_checks();
167        })
168    }
169
170    #[doc = include_str!("../docs/routing/route.md")]
171    #[track_caller]
172    pub fn route(self, path: &str, method_router: MethodRouter<S>) -> Self {
173        tap_inner!(self, mut this => {
174            panic_on_err!(this.path_router.route(path, method_router));
175        })
176    }
177
178    #[doc = include_str!("../docs/routing/route_service.md")]
179    pub fn route_service<T>(self, path: &str, service: T) -> Self
180    where
181        T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
182        T::Response: IntoResponse,
183        T::Future: Send + 'static,
184    {
185        let service = match try_downcast::<Router<S>, _>(service) {
186            Ok(_) => {
187                panic!(
188                    "Invalid route: `Router::route_service` cannot be used with `Router`s. \
189                     Use `Router::nest` instead"
190                );
191            }
192            Err(service) => service,
193        };
194
195        tap_inner!(self, mut this => {
196            panic_on_err!(this.path_router.route_service(path, service));
197        })
198    }
199
200    #[doc = include_str!("../docs/routing/nest.md")]
201    #[doc(alias = "scope")] // Some web frameworks like actix-web use this term
202    #[track_caller]
203    pub fn nest(self, path: &str, router: Router<S>) -> Self {
204        if path.is_empty() || path == "/" {
205            panic!("Nesting at the root is no longer supported. Use merge instead.");
206        }
207
208        let RouterInner {
209            path_router,
210            fallback_router,
211            default_fallback,
212            // we don't need to inherit the catch-all fallback. It is only used for CONNECT
213            // requests with an empty path. If we were to inherit the catch-all fallback
214            // it would end up matching `/{path}/*` which doesn't match empty paths.
215            catch_all_fallback: _,
216        } = router.into_inner();
217
218        tap_inner!(self, mut this => {
219            panic_on_err!(this.path_router.nest(path, path_router));
220
221            if !default_fallback {
222                panic_on_err!(this.fallback_router.nest(path, fallback_router));
223            }
224        })
225    }
226
227    /// Like [`nest`](Self::nest), but accepts an arbitrary `Service`.
228    #[track_caller]
229    pub fn nest_service<T>(self, path: &str, service: T) -> Self
230    where
231        T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
232        T::Response: IntoResponse,
233        T::Future: Send + 'static,
234    {
235        if path.is_empty() || path == "/" {
236            panic!("Nesting at the root is no longer supported. Use fallback_service instead.");
237        }
238
239        tap_inner!(self, mut this => {
240            panic_on_err!(this.path_router.nest_service(path, service));
241        })
242    }
243
244    #[doc = include_str!("../docs/routing/merge.md")]
245    #[track_caller]
246    pub fn merge<R>(self, other: R) -> Self
247    where
248        R: Into<Router<S>>,
249    {
250        const PANIC_MSG: &str =
251            "Failed to merge fallbacks. This is a bug in axum. Please file an issue";
252
253        let other: Router<S> = other.into();
254        let RouterInner {
255            path_router,
256            fallback_router: mut other_fallback,
257            default_fallback,
258            catch_all_fallback,
259        } = other.into_inner();
260
261        map_inner!(self, mut this => {
262            panic_on_err!(this.path_router.merge(path_router));
263
264            match (this.default_fallback, default_fallback) {
265                // both have the default fallback
266                // use the one from other
267                (true, true) => {
268                    this.fallback_router.merge(other_fallback).expect(PANIC_MSG);
269                }
270                // this has default fallback, other has a custom fallback
271                (true, false) => {
272                    this.fallback_router.merge(other_fallback).expect(PANIC_MSG);
273                    this.default_fallback = false;
274                }
275                // this has a custom fallback, other has a default
276                (false, true) => {
277                    let fallback_router = std::mem::take(&mut this.fallback_router);
278                    other_fallback.merge(fallback_router).expect(PANIC_MSG);
279                    this.fallback_router = other_fallback;
280                }
281                // both have a custom fallback, not allowed
282                (false, false) => {
283                    panic!("Cannot merge two `Router`s that both have a fallback")
284                }
285            };
286
287            this.catch_all_fallback = this
288                .catch_all_fallback
289                .merge(catch_all_fallback)
290                .unwrap_or_else(|| panic!("Cannot merge two `Router`s that both have a fallback"));
291
292            this
293        })
294    }
295
296    #[doc = include_str!("../docs/routing/layer.md")]
297    pub fn layer<L>(self, layer: L) -> Router<S>
298    where
299        L: Layer<Route> + Clone + Send + Sync + 'static,
300        L::Service: Service<Request> + Clone + Send + Sync + 'static,
301        <L::Service as Service<Request>>::Response: IntoResponse + 'static,
302        <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
303        <L::Service as Service<Request>>::Future: Send + 'static,
304    {
305        map_inner!(self, this => RouterInner {
306            path_router: this.path_router.layer(layer.clone()),
307            fallback_router: this.fallback_router.layer(layer.clone()),
308            default_fallback: this.default_fallback,
309            catch_all_fallback: this.catch_all_fallback.map(|route| route.layer(layer)),
310        })
311    }
312
313    #[doc = include_str!("../docs/routing/route_layer.md")]
314    #[track_caller]
315    pub fn route_layer<L>(self, layer: L) -> Self
316    where
317        L: Layer<Route> + Clone + Send + Sync + 'static,
318        L::Service: Service<Request> + Clone + Send + Sync + 'static,
319        <L::Service as Service<Request>>::Response: IntoResponse + 'static,
320        <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
321        <L::Service as Service<Request>>::Future: Send + 'static,
322    {
323        map_inner!(self, this => RouterInner {
324            path_router: this.path_router.route_layer(layer),
325            fallback_router: this.fallback_router,
326            default_fallback: this.default_fallback,
327            catch_all_fallback: this.catch_all_fallback,
328        })
329    }
330
331    /// True if the router currently has at least one route added.
332    pub fn has_routes(&self) -> bool {
333        self.inner.path_router.has_routes()
334    }
335
336    #[track_caller]
337    #[doc = include_str!("../docs/routing/fallback.md")]
338    pub fn fallback<H, T>(self, handler: H) -> Self
339    where
340        H: Handler<T, S>,
341        T: 'static,
342    {
343        tap_inner!(self, mut this => {
344            this.catch_all_fallback =
345                Fallback::BoxedHandler(BoxedIntoRoute::from_handler(handler.clone()));
346        })
347        .fallback_endpoint(Endpoint::MethodRouter(any(handler)))
348    }
349
350    /// Add a fallback [`Service`] to the router.
351    ///
352    /// See [`Router::fallback`] for more details.
353    pub fn fallback_service<T>(self, service: T) -> Self
354    where
355        T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
356        T::Response: IntoResponse,
357        T::Future: Send + 'static,
358    {
359        let route = Route::new(service);
360        tap_inner!(self, mut this => {
361            this.catch_all_fallback = Fallback::Service(route.clone());
362        })
363        .fallback_endpoint(Endpoint::Route(route))
364    }
365
366    #[doc = include_str!("../docs/routing/method_not_allowed_fallback.md")]
367    pub fn method_not_allowed_fallback<H, T>(self, handler: H) -> Self
368    where
369        H: Handler<T, S>,
370        T: 'static,
371    {
372        tap_inner!(self, mut this => {
373            this.path_router
374                .method_not_allowed_fallback(handler.clone())
375        })
376    }
377
378    fn fallback_endpoint(self, endpoint: Endpoint<S>) -> Self {
379        tap_inner!(self, mut this => {
380            this.fallback_router.set_fallback(endpoint);
381            this.default_fallback = false;
382        })
383    }
384
385    #[doc = include_str!("../docs/routing/with_state.md")]
386    pub fn with_state<S2>(self, state: S) -> Router<S2> {
387        map_inner!(self, this => RouterInner {
388            path_router: this.path_router.with_state(state.clone()),
389            fallback_router: this.fallback_router.with_state(state.clone()),
390            default_fallback: this.default_fallback,
391            catch_all_fallback: this.catch_all_fallback.with_state(state),
392        })
393    }
394
395    pub(crate) fn call_with_state(&self, req: Request, state: S) -> RouteFuture<Infallible> {
396        let (req, state) = match self.inner.path_router.call_with_state(req, state) {
397            Ok(future) => return future,
398            Err((req, state)) => (req, state),
399        };
400
401        let (req, state) = match self.inner.fallback_router.call_with_state(req, state) {
402            Ok(future) => return future,
403            Err((req, state)) => (req, state),
404        };
405
406        self.inner
407            .catch_all_fallback
408            .clone()
409            .call_with_state(req, state)
410    }
411
412    /// Convert the router into a borrowed [`Service`] with a fixed request body type, to aid type
413    /// inference.
414    ///
415    /// In some cases when calling methods from [`tower::ServiceExt`] on a [`Router`] you might get
416    /// type inference errors along the lines of
417    ///
418    /// ```not_rust
419    /// let response = router.ready().await?.call(request).await?;
420    ///                       ^^^^^ cannot infer type for type parameter `B`
421    /// ```
422    ///
423    /// This happens because `Router` implements [`Service`] with `impl<B> Service<Request<B>> for Router<()>`.
424    ///
425    /// For example:
426    ///
427    /// ```compile_fail
428    /// use axum::{
429    ///     Router,
430    ///     routing::get,
431    ///     http::Request,
432    ///     body::Body,
433    /// };
434    /// use tower::{Service, ServiceExt};
435    ///
436    /// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
437    /// let mut router = Router::new().route("/", get(|| async {}));
438    /// let request = Request::new(Body::empty());
439    /// let response = router.ready().await?.call(request).await?;
440    /// # Ok(())
441    /// # }
442    /// ```
443    ///
444    /// Calling `Router::as_service` fixes that:
445    ///
446    /// ```
447    /// use axum::{
448    ///     Router,
449    ///     routing::get,
450    ///     http::Request,
451    ///     body::Body,
452    /// };
453    /// use tower::{Service, ServiceExt};
454    ///
455    /// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
456    /// let mut router = Router::new().route("/", get(|| async {}));
457    /// let request = Request::new(Body::empty());
458    /// let response = router.as_service().ready().await?.call(request).await?;
459    /// # Ok(())
460    /// # }
461    /// ```
462    ///
463    /// This is mainly used when calling `Router` in tests. It shouldn't be necessary when running
464    /// the `Router` normally via [`Router::into_make_service`].
465    pub fn as_service<B>(&mut self) -> RouterAsService<'_, B, S> {
466        RouterAsService {
467            router: self,
468            _marker: PhantomData,
469        }
470    }
471
472    /// Convert the router into an owned [`Service`] with a fixed request body type, to aid type
473    /// inference.
474    ///
475    /// This is the same as [`Router::as_service`] instead it returns an owned [`Service`]. See
476    /// that method for more details.
477    pub fn into_service<B>(self) -> RouterIntoService<B, S> {
478        RouterIntoService {
479            router: self,
480            _marker: PhantomData,
481        }
482    }
483}
484
485impl Router {
486    /// Convert this router into a [`MakeService`], that is a [`Service`] whose
487    /// response is another service.
488    ///
489    /// ```
490    /// use axum::{
491    ///     routing::get,
492    ///     Router,
493    /// };
494    ///
495    /// let app = Router::new().route("/", get(|| async { "Hi!" }));
496    ///
497    /// # async {
498    /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
499    /// axum::serve(listener, app).await.unwrap();
500    /// # };
501    /// ```
502    ///
503    /// [`MakeService`]: tower::make::MakeService
504    pub fn into_make_service(self) -> IntoMakeService<Self> {
505        // call `Router::with_state` such that everything is turned into `Route` eagerly
506        // rather than doing that per request
507        IntoMakeService::new(self.with_state(()))
508    }
509
510    #[doc = include_str!("../docs/routing/into_make_service_with_connect_info.md")]
511    #[cfg(feature = "tokio")]
512    pub fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C> {
513        // call `Router::with_state` such that everything is turned into `Route` eagerly
514        // rather than doing that per request
515        IntoMakeServiceWithConnectInfo::new(self.with_state(()))
516    }
517}
518
519// for `axum::serve(listener, router)`
520#[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))]
521const _: () = {
522    use crate::serve;
523
524    impl<L> Service<serve::IncomingStream<'_, L>> for Router<()>
525    where
526        L: serve::Listener,
527    {
528        type Response = Self;
529        type Error = Infallible;
530        type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
531
532        fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
533            Poll::Ready(Ok(()))
534        }
535
536        fn call(&mut self, _req: serve::IncomingStream<'_, L>) -> Self::Future {
537            // call `Router::with_state` such that everything is turned into `Route` eagerly
538            // rather than doing that per request
539            std::future::ready(Ok(self.clone().with_state(())))
540        }
541    }
542};
543
544impl<B> Service<Request<B>> for Router<()>
545where
546    B: HttpBody<Data = bytes::Bytes> + Send + 'static,
547    B::Error: Into<axum_core::BoxError>,
548{
549    type Response = Response;
550    type Error = Infallible;
551    type Future = RouteFuture<Infallible>;
552
553    #[inline]
554    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
555        Poll::Ready(Ok(()))
556    }
557
558    #[inline]
559    fn call(&mut self, req: Request<B>) -> Self::Future {
560        let req = req.map(Body::new);
561        self.call_with_state(req, ())
562    }
563}
564
565/// A [`Router`] converted into a borrowed [`Service`] with a fixed body type.
566///
567/// See [`Router::as_service`] for more details.
568pub struct RouterAsService<'a, B, S = ()> {
569    router: &'a mut Router<S>,
570    _marker: PhantomData<B>,
571}
572
573impl<B> Service<Request<B>> for RouterAsService<'_, B, ()>
574where
575    B: HttpBody<Data = bytes::Bytes> + Send + 'static,
576    B::Error: Into<axum_core::BoxError>,
577{
578    type Response = Response;
579    type Error = Infallible;
580    type Future = RouteFuture<Infallible>;
581
582    #[inline]
583    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
584        <Router as Service<Request<B>>>::poll_ready(self.router, cx)
585    }
586
587    #[inline]
588    fn call(&mut self, req: Request<B>) -> Self::Future {
589        self.router.call(req)
590    }
591}
592
593impl<B, S> fmt::Debug for RouterAsService<'_, B, S>
594where
595    S: fmt::Debug,
596{
597    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598        f.debug_struct("RouterAsService")
599            .field("router", &self.router)
600            .finish()
601    }
602}
603
604/// A [`Router`] converted into an owned [`Service`] with a fixed body type.
605///
606/// See [`Router::into_service`] for more details.
607pub struct RouterIntoService<B, S = ()> {
608    router: Router<S>,
609    _marker: PhantomData<B>,
610}
611
612impl<B, S> Clone for RouterIntoService<B, S>
613where
614    Router<S>: Clone,
615{
616    fn clone(&self) -> Self {
617        Self {
618            router: self.router.clone(),
619            _marker: PhantomData,
620        }
621    }
622}
623
624impl<B> Service<Request<B>> for RouterIntoService<B, ()>
625where
626    B: HttpBody<Data = bytes::Bytes> + Send + 'static,
627    B::Error: Into<axum_core::BoxError>,
628{
629    type Response = Response;
630    type Error = Infallible;
631    type Future = RouteFuture<Infallible>;
632
633    #[inline]
634    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
635        <Router as Service<Request<B>>>::poll_ready(&mut self.router, cx)
636    }
637
638    #[inline]
639    fn call(&mut self, req: Request<B>) -> Self::Future {
640        self.router.call(req)
641    }
642}
643
644impl<B, S> fmt::Debug for RouterIntoService<B, S>
645where
646    S: fmt::Debug,
647{
648    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649        f.debug_struct("RouterIntoService")
650            .field("router", &self.router)
651            .finish()
652    }
653}
654
655enum Fallback<S, E = Infallible> {
656    Default(Route<E>),
657    Service(Route<E>),
658    BoxedHandler(BoxedIntoRoute<S, E>),
659}
660
661impl<S, E> Fallback<S, E>
662where
663    S: Clone,
664{
665    fn merge(self, other: Self) -> Option<Self> {
666        match (self, other) {
667            (Self::Default(_), pick @ Self::Default(_)) => Some(pick),
668            (Self::Default(_), pick) | (pick, Self::Default(_)) => Some(pick),
669            _ => None,
670        }
671    }
672
673    fn map<F, E2>(self, f: F) -> Fallback<S, E2>
674    where
675        S: 'static,
676        E: 'static,
677        F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + Sync + 'static,
678        E2: 'static,
679    {
680        match self {
681            Self::Default(route) => Fallback::Default(f(route)),
682            Self::Service(route) => Fallback::Service(f(route)),
683            Self::BoxedHandler(handler) => Fallback::BoxedHandler(handler.map(f)),
684        }
685    }
686
687    fn with_state<S2>(self, state: S) -> Fallback<S2, E> {
688        match self {
689            Fallback::Default(route) => Fallback::Default(route),
690            Fallback::Service(route) => Fallback::Service(route),
691            Fallback::BoxedHandler(handler) => Fallback::Service(handler.into_route(state)),
692        }
693    }
694
695    fn call_with_state(self, req: Request, state: S) -> RouteFuture<E> {
696        match self {
697            Fallback::Default(route) | Fallback::Service(route) => route.oneshot_inner_owned(req),
698            Fallback::BoxedHandler(handler) => {
699                let route = handler.clone().into_route(state);
700                route.oneshot_inner_owned(req)
701            }
702        }
703    }
704}
705
706impl<S, E> Clone for Fallback<S, E> {
707    fn clone(&self) -> Self {
708        match self {
709            Self::Default(inner) => Self::Default(inner.clone()),
710            Self::Service(inner) => Self::Service(inner.clone()),
711            Self::BoxedHandler(inner) => Self::BoxedHandler(inner.clone()),
712        }
713    }
714}
715
716impl<S, E> fmt::Debug for Fallback<S, E> {
717    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
718        match self {
719            Self::Default(inner) => f.debug_tuple("Default").field(inner).finish(),
720            Self::Service(inner) => f.debug_tuple("Service").field(inner).finish(),
721            Self::BoxedHandler(_) => f.debug_tuple("BoxedHandler").finish(),
722        }
723    }
724}
725
726#[allow(clippy::large_enum_variant)]
727enum Endpoint<S> {
728    MethodRouter(MethodRouter<S>),
729    Route(Route),
730}
731
732impl<S> Endpoint<S>
733where
734    S: Clone + Send + Sync + 'static,
735{
736    fn layer<L>(self, layer: L) -> Endpoint<S>
737    where
738        L: Layer<Route> + Clone + Send + Sync + 'static,
739        L::Service: Service<Request> + Clone + Send + Sync + 'static,
740        <L::Service as Service<Request>>::Response: IntoResponse + 'static,
741        <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
742        <L::Service as Service<Request>>::Future: Send + 'static,
743    {
744        match self {
745            Endpoint::MethodRouter(method_router) => {
746                Endpoint::MethodRouter(method_router.layer(layer))
747            }
748            Endpoint::Route(route) => Endpoint::Route(route.layer(layer)),
749        }
750    }
751}
752
753impl<S> Clone for Endpoint<S> {
754    fn clone(&self) -> Self {
755        match self {
756            Self::MethodRouter(inner) => Self::MethodRouter(inner.clone()),
757            Self::Route(inner) => Self::Route(inner.clone()),
758        }
759    }
760}
761
762impl<S> fmt::Debug for Endpoint<S> {
763    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764        match self {
765            Self::MethodRouter(method_router) => {
766                f.debug_tuple("MethodRouter").field(method_router).finish()
767            }
768            Self::Route(route) => f.debug_tuple("Route").field(route).finish(),
769        }
770    }
771}
772
773#[test]
774fn traits() {
775    use crate::test_helpers::*;
776    assert_send::<Router<()>>();
777    assert_sync::<Router<()>>();
778}