mirror of
https://github.com/tokio-rs/axum.git
synced 2025-03-08 08:56:24 +01:00
parent
8013165908
commit
b4bdddf9d2
6 changed files with 86 additions and 2 deletions
|
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Implement `std::error::Error` for all rejections ([#153](https://github.com/tokio-rs/axum/pull/153))
|
||||
- Add `RoutingDsl::or` for combining routes ([#108](https://github.com/tokio-rs/axum/pull/108))
|
||||
- Add `handle_error` to `service::OnMethod` ([#160](https://github.com/tokio-rs/axum/pull/160))
|
||||
- Add `NestedUri` for extracting request URI in nested services ([#161](https://github.com/tokio-rs/axum/pull/161))
|
||||
|
||||
## Breaking changes
|
||||
|
||||
|
|
|
@ -278,6 +278,7 @@ pub use self::{
|
|||
path::Path,
|
||||
query::Query,
|
||||
raw_query::RawQuery,
|
||||
request_parts::NestedUri,
|
||||
request_parts::{Body, BodyStream},
|
||||
};
|
||||
#[doc(no_inline)]
|
||||
|
|
|
@ -108,6 +108,16 @@ define_rejection! {
|
|||
pub struct InvalidFormContentType;
|
||||
}
|
||||
|
||||
define_rejection! {
|
||||
#[status = INTERNAL_SERVER_ERROR]
|
||||
#[body = "`NestedUri` extractor used for route that isn't nested"]
|
||||
/// Rejection type used if you try and extract [`NestedUri`] from a route that
|
||||
/// isn't nested.
|
||||
///
|
||||
/// [`NestedUri`]: crate::extract::NestedUri
|
||||
pub struct NotNested;
|
||||
}
|
||||
|
||||
/// Rejection type for [`Path`](super::Path) if the capture route
|
||||
/// param didn't have the expected type.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{rejection::*, take_body, FromRequest, RequestParts};
|
||||
use super::{rejection::*, take_body, Extension, FromRequest, RequestParts};
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use futures_util::stream::Stream;
|
||||
|
@ -74,6 +74,48 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Extractor that gets the request URI for a nested service.
|
||||
///
|
||||
/// This is necessary since [`Uri`](http::Uri), when used as an extractor, will
|
||||
/// always be the full URI.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{prelude::*, extract::NestedUri, http::Uri};
|
||||
///
|
||||
/// let api_routes = route(
|
||||
/// "/users",
|
||||
/// get(|uri: Uri, NestedUri(nested_uri): NestedUri| async {
|
||||
/// // `uri` is `/api/users`
|
||||
/// // `nested_uri` is `/users`
|
||||
/// }),
|
||||
/// );
|
||||
///
|
||||
/// let app = nest("/api", api_routes);
|
||||
/// # async {
|
||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NestedUri(pub Uri);
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for NestedUri
|
||||
where
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = NotNested;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
let uri = Extension::<Self>::from_request(req)
|
||||
.await
|
||||
.map_err(|_| NotNested)?
|
||||
.0;
|
||||
Ok(uri)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Version
|
||||
where
|
||||
|
|
|
@ -4,7 +4,10 @@ use self::future::{BoxRouteFuture, EmptyRouterFuture, NestedFuture, RouteFuture}
|
|||
use crate::{
|
||||
body::{box_body, BoxBody},
|
||||
buffer::MpscBuffer,
|
||||
extract::connect_info::{Connected, IntoMakeServiceWithConnectInfo},
|
||||
extract::{
|
||||
connect_info::{Connected, IntoMakeServiceWithConnectInfo},
|
||||
NestedUri,
|
||||
},
|
||||
response::IntoResponse,
|
||||
service::{HandleError, HandleErrorFromRouter},
|
||||
util::ByteStr,
|
||||
|
@ -868,6 +871,8 @@ where
|
|||
|
||||
let f = if let Some((prefix, captures)) = self.pattern.prefix_match(req.uri().path()) {
|
||||
let without_prefix = strip_prefix(req.uri(), prefix);
|
||||
req.extensions_mut()
|
||||
.insert(NestedUri(without_prefix.clone()));
|
||||
*req.uri_mut() = without_prefix;
|
||||
|
||||
insert_url_params(&mut req, captures);
|
||||
|
|
|
@ -158,3 +158,28 @@ async fn nested_url_extractor() {
|
|||
.unwrap();
|
||||
assert_eq!(res.text().await.unwrap(), "/foo/bar/qux");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn nested_url_nested_extractor() {
|
||||
let app = nest(
|
||||
"/foo",
|
||||
nest(
|
||||
"/bar",
|
||||
route(
|
||||
"/baz",
|
||||
get(|uri: extract::NestedUri| async move { uri.0.to_string() }),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
let addr = run_in_background(app).await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let res = client
|
||||
.get(format!("http://{}/foo/bar/baz", addr))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res.text().await.unwrap(), "/baz");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue