axum/extract/original_uri.rs
1use super::{Extension, FromRequestParts};
2use http::{request::Parts, Uri};
3use std::convert::Infallible;
4
5/// Extractor that gets the original request URI regardless of nesting.
6///
7/// This is necessary since [`Uri`](http::Uri), when used as an extractor, will
8/// have the prefix stripped if used in a nested service.
9///
10/// # Example
11///
12/// ```
13/// use axum::{
14/// routing::get,
15/// Router,
16/// extract::OriginalUri,
17/// http::Uri
18/// };
19///
20/// let api_routes = Router::new()
21/// .route(
22/// "/users",
23/// get(|uri: Uri, OriginalUri(original_uri): OriginalUri| async {
24/// // `uri` is `/users`
25/// // `original_uri` is `/api/users`
26/// }),
27/// );
28///
29/// let app = Router::new().nest("/api", api_routes);
30/// # let _: Router = app;
31/// ```
32///
33/// # Extracting via request extensions
34///
35/// `OriginalUri` can also be accessed from middleware via request extensions.
36/// This is useful for example with [`Trace`](tower_http::trace::Trace) to
37/// create a span that contains the full path, if your service might be nested:
38///
39/// ```
40/// use axum::{
41/// Router,
42/// extract::OriginalUri,
43/// http::Request,
44/// routing::get,
45/// };
46/// use tower_http::trace::TraceLayer;
47///
48/// let api_routes = Router::new()
49/// .route("/users/{id}", get(|| async { /* ... */ }))
50/// .layer(
51/// TraceLayer::new_for_http().make_span_with(|req: &Request<_>| {
52/// let path = if let Some(path) = req.extensions().get::<OriginalUri>() {
53/// // This will include `/api`
54/// path.0.path().to_owned()
55/// } else {
56/// // The `OriginalUri` extension will always be present if using
57/// // `Router` unless another extractor or middleware has removed it
58/// req.uri().path().to_owned()
59/// };
60/// tracing::info_span!("http-request", %path)
61/// }),
62/// );
63///
64/// let app = Router::new().nest("/api", api_routes);
65/// # let _: Router = app;
66/// ```
67#[derive(Debug, Clone)]
68pub struct OriginalUri(pub Uri);
69
70impl<S> FromRequestParts<S> for OriginalUri
71where
72 S: Send + Sync,
73{
74 type Rejection = Infallible;
75
76 async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
77 let uri = Extension::<Self>::from_request_parts(parts, state)
78 .await
79 .unwrap_or_else(|_| Extension(OriginalUri(parts.uri.clone())))
80 .0;
81 Ok(uri)
82 }
83}
84
85axum_core::__impl_deref!(OriginalUri: Uri);