mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-08 00:00:24 +02:00
add state parameter to router
This commit is contained in:
@@ -272,3 +272,19 @@ where
|
|||||||
Ok(T::from_request(req).await)
|
Ok(T::from_request(req).await)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO(david): docs
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct State<S>(pub S);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<S, B> FromRequest<B> for State<S>
|
||||||
|
where
|
||||||
|
B: Send,
|
||||||
|
{
|
||||||
|
type Rejection = Infallible;
|
||||||
|
|
||||||
|
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -226,12 +226,13 @@ mod tests {
|
|||||||
jar.remove(Cookie::named("key"))
|
jar.remove(Cookie::named("key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::<Body>::new()
|
let app = Router::<_, Body, _>::new()
|
||||||
.route("/set", get(set_cookie))
|
.route("/set", get(set_cookie))
|
||||||
.route("/get", get(get_cookie))
|
.route("/get", get(get_cookie))
|
||||||
.route("/remove", get(remove_cookie))
|
.route("/remove", get(remove_cookie))
|
||||||
.layer(Extension(Key::generate()))
|
.layer(Extension(Key::generate()))
|
||||||
.layer(Extension(CustomKey(Key::generate())));
|
.layer(Extension(CustomKey(Key::generate())))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let res = app
|
let res = app
|
||||||
.clone()
|
.clone()
|
||||||
@@ -294,9 +295,10 @@ mod tests {
|
|||||||
format!("{:?}", jar.get("key"))
|
format!("{:?}", jar.get("key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::<Body>::new()
|
let app = Router::<_, Body, _>::new()
|
||||||
.route("/get", get(get_cookie))
|
.route("/get", get(get_cookie))
|
||||||
.layer(Extension(Key::generate()));
|
.layer(Extension(Key::generate()))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let res = app
|
let res = app
|
||||||
.clone()
|
.clone()
|
||||||
|
|||||||
@@ -116,10 +116,12 @@ mod tests {
|
|||||||
values: Vec<String>,
|
values: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/",
|
.route(
|
||||||
post(|Form(data): Form<Data>| async move { data.values.join(",") }),
|
"/",
|
||||||
);
|
post(|Form(data): Form<Data>| async move { data.values.join(",") }),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -97,10 +97,12 @@ mod tests {
|
|||||||
values: Vec<String>,
|
values: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/",
|
.route(
|
||||||
post(|Query(data): Query<Data>| async move { data.values.join(",") }),
|
"/",
|
||||||
);
|
post(|Query(data): Query<Data>| async move { data.values.join(",") }),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -217,22 +217,24 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extractor() {
|
async fn extractor() {
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/",
|
.route(
|
||||||
post(|mut stream: JsonLines<User>| async move {
|
"/",
|
||||||
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 1 });
|
post(|mut stream: JsonLines<User>| async move {
|
||||||
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 2 });
|
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 1 });
|
||||||
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 3 });
|
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 2 });
|
||||||
|
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 3 });
|
||||||
|
|
||||||
// sources are downcastable to `serde_json::Error`
|
// sources are downcastable to `serde_json::Error`
|
||||||
let err = stream.next().await.unwrap().unwrap_err();
|
let err = stream.next().await.unwrap().unwrap_err();
|
||||||
let _: &serde_json::Error = err
|
let _: &serde_json::Error = err
|
||||||
.source()
|
.source()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.downcast_ref::<serde_json::Error>()
|
.downcast_ref::<serde_json::Error>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -255,17 +257,19 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn response() {
|
async fn response() {
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/",
|
.route(
|
||||||
get(|| async {
|
"/",
|
||||||
let values = futures_util::stream::iter(vec![
|
get(|| async {
|
||||||
Ok::<_, Infallible>(User { id: 1 }),
|
let values = futures_util::stream::iter(vec![
|
||||||
Ok::<_, Infallible>(User { id: 2 }),
|
Ok::<_, Infallible>(User { id: 1 }),
|
||||||
Ok::<_, Infallible>(User { id: 3 }),
|
Ok::<_, Infallible>(User { id: 2 }),
|
||||||
]);
|
Ok::<_, Infallible>(User { id: 3 }),
|
||||||
JsonLines::new(values)
|
]);
|
||||||
}),
|
JsonLines::new(values)
|
||||||
);
|
}),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub use self::typed::{FirstElementIs, TypedPath};
|
|||||||
pub use self::spa::SpaRouter;
|
pub use self::spa::SpaRouter;
|
||||||
|
|
||||||
/// Extension trait that adds additional methods to [`Router`].
|
/// Extension trait that adds additional methods to [`Router`].
|
||||||
pub trait RouterExt<B>: sealed::Sealed {
|
pub trait RouterExt<S, B, R>: sealed::Sealed {
|
||||||
/// Add a typed `GET` route to the router.
|
/// Add a typed `GET` route to the router.
|
||||||
///
|
///
|
||||||
/// The path will be inferred from the first argument to the handler function which must
|
/// The path will be inferred from the first argument to the handler function which must
|
||||||
@@ -166,9 +166,11 @@ pub trait RouterExt<B>: sealed::Sealed {
|
|||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> RouterExt<B> for Router<B>
|
impl<S, B, R> RouterExt<S, B, R> for Router<S, B, R>
|
||||||
where
|
where
|
||||||
B: axum::body::HttpBody + Send + 'static,
|
B: axum::body::HttpBody + Send + 'static,
|
||||||
|
R: 'static,
|
||||||
|
S: 'static,
|
||||||
{
|
{
|
||||||
#[cfg(feature = "typed-routing")]
|
#[cfg(feature = "typed-routing")]
|
||||||
fn typed_get<H, T, P>(self, handler: H) -> Self
|
fn typed_get<H, T, P>(self, handler: H) -> Self
|
||||||
@@ -276,7 +278,7 @@ where
|
|||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
impl<B> Sealed for axum::Router<B> {}
|
impl<S, B, R> Sealed for axum::Router<S, B, R> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -289,7 +291,8 @@ mod tests {
|
|||||||
async fn test_tsr() {
|
async fn test_tsr() {
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route_with_tsr("/foo", get(|| async {}))
|
.route_with_tsr("/foo", get(|| async {}))
|
||||||
.route_with_tsr("/bar/", get(|| async {}));
|
.route_with_tsr("/bar/", get(|| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use axum::{
|
|||||||
handler::Handler,
|
handler::Handler,
|
||||||
http::Request,
|
http::Request,
|
||||||
response::Response,
|
response::Response,
|
||||||
routing::{delete, get, on, post, MethodFilter},
|
routing::{delete, get, on, post, MethodFilter, MissingState, WithState},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use std::convert::Infallible;
|
use std::{convert::Infallible, fmt};
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
/// A resource which defines a set of conventional CRUD routes.
|
/// A resource which defines a set of conventional CRUD routes.
|
||||||
@@ -47,13 +47,24 @@ use tower_service::Service;
|
|||||||
/// let app = Router::new().merge(users);
|
/// let app = Router::new().merge(users);
|
||||||
/// # let _: Router<axum::body::Body> = app;
|
/// # let _: Router<axum::body::Body> = app;
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
pub struct Resource<S, B = Body, R = MissingState> {
|
||||||
pub struct Resource<B = Body> {
|
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
pub(crate) router: Router<B>,
|
pub(crate) router: Router<S, B, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Resource<B>
|
impl<S, B, R> fmt::Debug for Resource<S, B, R>
|
||||||
|
where
|
||||||
|
S: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Resource")
|
||||||
|
.field("name", &self.name)
|
||||||
|
.field("router", &self.router)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> Resource<S, B, MissingState>
|
||||||
where
|
where
|
||||||
B: axum::body::HttpBody + Send + 'static,
|
B: axum::body::HttpBody + Send + 'static,
|
||||||
{
|
{
|
||||||
@@ -67,6 +78,24 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO(david): docs
|
||||||
|
pub fn state(self, state: S) -> Resource<S, B, WithState>
|
||||||
|
where
|
||||||
|
S: Clone,
|
||||||
|
{
|
||||||
|
Resource {
|
||||||
|
name: self.name,
|
||||||
|
router: self.router.state(state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B, R> Resource<S, B, R>
|
||||||
|
where
|
||||||
|
B: axum::body::HttpBody + Send + 'static,
|
||||||
|
S: 'static,
|
||||||
|
R: 'static,
|
||||||
|
{
|
||||||
/// Add a handler at `GET /{resource_name}`.
|
/// Add a handler at `GET /{resource_name}`.
|
||||||
pub fn index<H, T>(self, handler: H) -> Self
|
pub fn index<H, T>(self, handler: H) -> Self
|
||||||
where
|
where
|
||||||
@@ -140,7 +169,7 @@ where
|
|||||||
/// Nest another router at the "member level".
|
/// Nest another router at the "member level".
|
||||||
///
|
///
|
||||||
/// The routes will be nested at `/{resource_name}/:{resource_name}_id`.
|
/// The routes will be nested at `/{resource_name}/:{resource_name}_id`.
|
||||||
pub fn nest(mut self, router: Router<B>) -> Self {
|
pub fn nest(mut self, router: Router<S, B, MissingState>) -> Self {
|
||||||
let path = self.show_update_destroy_path();
|
let path = self.show_update_destroy_path();
|
||||||
self.router = self.router.nest(&path, router);
|
self.router = self.router.nest(&path, router);
|
||||||
self
|
self
|
||||||
@@ -149,7 +178,7 @@ where
|
|||||||
/// Nest another router at the "collection level".
|
/// Nest another router at the "collection level".
|
||||||
///
|
///
|
||||||
/// The routes will be nested at `/{resource_name}`.
|
/// The routes will be nested at `/{resource_name}`.
|
||||||
pub fn nest_collection(mut self, router: Router<B>) -> Self {
|
pub fn nest_collection(mut self, router: Router<S, B, MissingState>) -> Self {
|
||||||
let path = self.index_create_path();
|
let path = self.index_create_path();
|
||||||
self.router = self.router.nest(&path, router);
|
self.router = self.router.nest(&path, router);
|
||||||
self
|
self
|
||||||
@@ -173,8 +202,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> From<Resource<B>> for Router<B> {
|
impl<S, B> From<Resource<S, B, MissingState>> for Router<S, B, MissingState> {
|
||||||
fn from(resource: Resource<B>) -> Self {
|
fn from(resource: Resource<S, B, MissingState>) -> Self {
|
||||||
resource.router
|
resource.router
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,7 +233,7 @@ mod tests {
|
|||||||
Router::new().route("/featured", get(|| async move { "users#featured" })),
|
Router::new().route("/featured", get(|| async move { "users#featured" })),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut app = Router::new().merge(users);
|
let mut app = Router::new().merge(users).state(());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
call_route(&mut app, Method::GET, "/users").await,
|
call_route(&mut app, Method::GET, "/users").await,
|
||||||
@@ -257,7 +286,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn call_route(app: &mut Router, method: Method, uri: &str) -> String {
|
async fn call_route(
|
||||||
|
app: &mut Router<(), Body, axum::routing::WithState>,
|
||||||
|
method: Method,
|
||||||
|
uri: &str,
|
||||||
|
) -> String {
|
||||||
let res = app
|
let res = app
|
||||||
.ready()
|
.ready()
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use axum::{
|
|||||||
body::{Body, HttpBody},
|
body::{Body, HttpBody},
|
||||||
error_handling::HandleError,
|
error_handling::HandleError,
|
||||||
response::Response,
|
response::Response,
|
||||||
routing::{get_service, Route},
|
routing::{get_service, MissingState, Route},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use http::{Request, StatusCode};
|
use http::{Request, StatusCode};
|
||||||
@@ -147,7 +147,7 @@ impl<B, T, F> SpaRouter<B, T, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, F, T> From<SpaRouter<B, T, F>> for Router<B>
|
impl<B, F, T, S> From<SpaRouter<B, T, F>> for Router<S, B, MissingState>
|
||||||
where
|
where
|
||||||
F: Clone + Send + 'static,
|
F: Clone + Send + 'static,
|
||||||
HandleError<Route<B, io::Error>, F, T>:
|
HandleError<Route<B, io::Error>, F, T>:
|
||||||
@@ -155,6 +155,7 @@ where
|
|||||||
<HandleError<Route<B, io::Error>, F, T> as Service<Request<B>>>::Future: Send,
|
<HandleError<Route<B, io::Error>, F, T> as Service<Request<B>>>::Future: Send,
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
T: 'static,
|
T: 'static,
|
||||||
|
S: 'static,
|
||||||
{
|
{
|
||||||
fn from(spa: SpaRouter<B, T, F>) -> Self {
|
fn from(spa: SpaRouter<B, T, F>) -> Self {
|
||||||
let assets_service = get_service(ServeDir::new(&spa.paths.assets_dir))
|
let assets_service = get_service(ServeDir::new(&spa.paths.assets_dir))
|
||||||
@@ -214,7 +215,8 @@ mod tests {
|
|||||||
async fn basic() {
|
async fn basic() {
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/foo", get(|| async { "GET /foo" }))
|
.route("/foo", get(|| async { "GET /foo" }))
|
||||||
.merge(SpaRouter::new("/assets", "test_files"));
|
.merge(SpaRouter::new("/assets", "test_files"))
|
||||||
|
.state(());
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
@@ -239,8 +241,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn setting_index_file() {
|
async fn setting_index_file() {
|
||||||
let app =
|
let app = Router::new()
|
||||||
Router::new().merge(SpaRouter::new("/assets", "test_files").index_file("index_2.html"));
|
.merge(SpaRouter::new("/assets", "test_files").index_file("index_2.html"))
|
||||||
|
.state(());
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
@@ -264,6 +267,6 @@ mod tests {
|
|||||||
|
|
||||||
let spa = SpaRouter::new("/assets", "test_files").handle_error(handle_error);
|
let spa = SpaRouter::new("/assets", "test_files").handle_error(handle_error);
|
||||||
|
|
||||||
Router::<Body>::new().merge(spa);
|
Router::<(), Body, _>::new().merge(spa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ mod tests {
|
|||||||
|
|
||||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let app = Router::new().route("/", get(handler));
|
let app = Router::new().route("/", get(handler)).state(());
|
||||||
let server = Server::from_tcp(listener)
|
let server = Server::from_tcp(listener)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.serve(app.into_make_service_with_connect_info::<SocketAddr>());
|
.serve(app.into_make_service_with_connect_info::<SocketAddr>());
|
||||||
@@ -198,7 +198,7 @@ mod tests {
|
|||||||
|
|
||||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let app = Router::new().route("/", get(handler));
|
let app = Router::new().route("/", get(handler)).state(());
|
||||||
let server = Server::from_tcp(listener)
|
let server = Server::from_tcp(listener)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.serve(app.into_make_service_with_connect_info::<MyConnectInfo>());
|
.serve(app.into_make_service_with_connect_info::<MyConnectInfo>());
|
||||||
|
|||||||
@@ -115,10 +115,12 @@ mod tests {
|
|||||||
|
|
||||||
const LIMIT: u64 = 8;
|
const LIMIT: u64 = 8;
|
||||||
|
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/",
|
.route(
|
||||||
post(|_body: ContentLengthLimit<Bytes, LIMIT>| async {}),
|
"/",
|
||||||
);
|
post(|_body: ContentLengthLimit<Bytes, LIMIT>| async {}),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
let res = client
|
let res = client
|
||||||
@@ -154,7 +156,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_request_without_content_length_is_accepted() {
|
async fn get_request_without_content_length_is_accepted() {
|
||||||
let app = Router::new().route("/", get(|_body: ContentLengthLimit<Bytes, 1337>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/", get(|_body: ContentLengthLimit<Bytes, 1337>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -164,7 +168,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_request_with_content_length_is_rejected() {
|
async fn get_request_with_content_length_is_rejected() {
|
||||||
let app = Router::new().route("/", get(|_body: ContentLengthLimit<Bytes, 1337>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/", get(|_body: ContentLengthLimit<Bytes, 1337>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -179,7 +185,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_request_with_chunked_encoding_is_rejected() {
|
async fn get_request_with_chunked_encoding_is_rejected() {
|
||||||
let app = Router::new().route("/", get(|_body: ContentLengthLimit<Bytes, 1337>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/", get(|_body: ContentLengthLimit<Bytes, 1337>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ mod tests {
|
|||||||
host
|
host
|
||||||
}
|
}
|
||||||
|
|
||||||
TestClient::new(Router::new().route("/", get(host_as_body)))
|
TestClient::new(Router::new().route("/", get(host_as_body)).state(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ mod tests {
|
|||||||
Router::new().route("/assets/*path", get(handler)),
|
Router::new().route("/assets/*path", get(handler)),
|
||||||
)
|
)
|
||||||
.nest_service("/foo", handler.into_service())
|
.nest_service("/foo", handler.into_service())
|
||||||
.layer(tower::layer::layer_fn(SetMatchedPathExtension));
|
.layer(tower::layer::layer_fn(SetMatchedPathExtension))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -181,13 +182,17 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn nested_opaque_routers_append_to_matched_path() {
|
async fn nested_opaque_routers_append_to_matched_path() {
|
||||||
let app = Router::new().nest_service(
|
let app = Router::new()
|
||||||
"/:a",
|
.nest_service(
|
||||||
Router::new().route(
|
"/:a",
|
||||||
"/:b",
|
Router::new()
|
||||||
get(|path: MatchedPath| async move { path.as_str().to_owned() }),
|
.route(
|
||||||
),
|
"/:b",
|
||||||
);
|
get(|path: MatchedPath| async move { path.as_str().to_owned() }),
|
||||||
|
)
|
||||||
|
.state(()),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ mod raw_query;
|
|||||||
mod request_parts;
|
mod request_parts;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use axum_core::extract::{FromRequest, RequestParts};
|
pub use axum_core::extract::{FromRequest, RequestParts, State};
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
@@ -103,7 +103,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn consume_body() {
|
async fn consume_body() {
|
||||||
let app = Router::new().route("/", get(|body: String| async { body }));
|
let app = Router::new()
|
||||||
|
.route("/", get(|body: String| async { body }))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
let res = client.get("/").body("foo").send().await;
|
let res = client.get("/").body("foo").send().await;
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ mod tests {
|
|||||||
assert!(multipart.next_field().await.unwrap().is_none());
|
assert!(multipart.next_field().await.unwrap().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new().route("/", post(handle));
|
let app = Router::new().route("/", post(handle)).state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -418,15 +418,17 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extracting_url_params() {
|
async fn extracting_url_params() {
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/users/:id",
|
.route(
|
||||||
get(|Path(id): Path<i32>| async move {
|
"/users/:id",
|
||||||
assert_eq!(id, 42);
|
get(|Path(id): Path<i32>| async move {
|
||||||
})
|
assert_eq!(id, 42);
|
||||||
.post(|Path(params_map): Path<HashMap<String, i32>>| async move {
|
})
|
||||||
assert_eq!(params_map.get("id").unwrap(), &1337);
|
.post(|Path(params_map): Path<HashMap<String, i32>>| async move {
|
||||||
}),
|
assert_eq!(params_map.get("id").unwrap(), &1337);
|
||||||
);
|
}),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -439,7 +441,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extracting_url_params_multiple_times() {
|
async fn extracting_url_params_multiple_times() {
|
||||||
let app = Router::new().route("/users/:id", get(|_: Path<i32>, _: Path<String>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/users/:id", get(|_: Path<i32>, _: Path<String>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -449,10 +453,12 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn percent_decoding() {
|
async fn percent_decoding() {
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/:key",
|
.route(
|
||||||
get(|Path(param): Path<String>| async move { param }),
|
"/:key",
|
||||||
);
|
get(|Path(param): Path<String>| async move { param }),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -471,7 +477,8 @@ mod tests {
|
|||||||
.route(
|
.route(
|
||||||
"/u/:key",
|
"/u/:key",
|
||||||
get(|Path(param): Path<u128>| async move { param.to_string() }),
|
get(|Path(param): Path<u128>| async move { param.to_string() }),
|
||||||
);
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -494,7 +501,8 @@ mod tests {
|
|||||||
get(|Path(params): Path<HashMap<String, String>>| async move {
|
get(|Path(params): Path<HashMap<String, String>>| async move {
|
||||||
params.get("rest").unwrap().clone()
|
params.get("rest").unwrap().clone()
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -507,7 +515,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn captures_dont_match_empty_segments() {
|
async fn captures_dont_match_empty_segments() {
|
||||||
let app = Router::new().route("/:key", get(|| async {}));
|
let app = Router::new().route("/:key", get(|| async {})).state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -520,7 +528,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn when_extensions_are_missing() {
|
async fn when_extensions_are_missing() {
|
||||||
let app = Router::new().route("/:key", get(|_: Request<Body>, _: Path<String>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/:key", get(|_: Request<Body>, _: Path<String>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -545,7 +555,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new().route("/:key", get(|param: Path<Param>| async move { param.0 .0 }));
|
let app = Router::new()
|
||||||
|
.route("/:key", get(|param: Path<Param>| async move { param.0 .0 }))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -559,7 +571,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn two_path_extractors() {
|
async fn two_path_extractors() {
|
||||||
let app = Router::new().route("/:a/:b", get(|_: Path<String>, _: Path<String>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/:a/:b", get(|_: Path<String>, _: Path<String>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -574,18 +588,20 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn deserialize_into_vec_of_tuples() {
|
async fn deserialize_into_vec_of_tuples() {
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/:a/:b",
|
.route(
|
||||||
get(|Path(params): Path<Vec<(String, String)>>| async move {
|
"/:a/:b",
|
||||||
assert_eq!(
|
get(|Path(params): Path<Vec<(String, String)>>| async move {
|
||||||
params,
|
assert_eq!(
|
||||||
vec![
|
params,
|
||||||
("a".to_owned(), "foo".to_owned()),
|
vec![
|
||||||
("b".to_owned(), "bar".to_owned())
|
("a".to_owned(), "foo".to_owned()),
|
||||||
]
|
("b".to_owned(), "bar".to_owned())
|
||||||
);
|
]
|
||||||
}),
|
);
|
||||||
);
|
}),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ mod tests {
|
|||||||
async fn multiple_request_extractors() {
|
async fn multiple_request_extractors() {
|
||||||
async fn handler(_: Request<Body>, _: Request<Body>) {}
|
async fn handler(_: Request<Body>, _: Request<Body>) {}
|
||||||
|
|
||||||
let app = Router::new().route("/", post(handler));
|
let app = Router::new().route("/", post(handler)).state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -248,7 +248,12 @@ mod tests {
|
|||||||
parts.extensions.get::<Ext>().unwrap();
|
parts.extensions.get::<Ext>().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = TestClient::new(Router::new().route("/", get(handler)).layer(Extension(Ext)));
|
let client = TestClient::new(
|
||||||
|
Router::new()
|
||||||
|
.route("/", get(handler))
|
||||||
|
.layer(Extension(Ext))
|
||||||
|
.state(()),
|
||||||
|
);
|
||||||
|
|
||||||
let res = client.get("/").header("x-foo", "123").send().await;
|
let res = client.get("/").header("x-foo", "123").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -263,7 +268,7 @@ mod tests {
|
|||||||
assert_eq!(body, "foo");
|
assert_eq!(body, "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = TestClient::new(Router::new().route("/", get(handler)));
|
let client = TestClient::new(Router::new().route("/", get(handler)).state(()));
|
||||||
|
|
||||||
let res = client.get("/").body("foo").send().await;
|
let res = client.get("/").body("foo").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
|||||||
+12
-4
@@ -221,7 +221,9 @@ mod tests {
|
|||||||
foo: String,
|
foo: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new().route("/", post(|input: Json<Input>| async { input.0.foo }));
|
let app = Router::new()
|
||||||
|
.route("/", post(|input: Json<Input>| async { input.0.foo }))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
let res = client.post("/").json(&json!({ "foo": "bar" })).send().await;
|
let res = client.post("/").json(&json!({ "foo": "bar" })).send().await;
|
||||||
@@ -237,7 +239,9 @@ mod tests {
|
|||||||
foo: String,
|
foo: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new().route("/", post(|input: Json<Input>| async { input.0.foo }));
|
let app = Router::new()
|
||||||
|
.route("/", post(|input: Json<Input>| async { input.0.foo }))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
let res = client.post("/").body(r#"{ "foo": "bar" }"#).send().await;
|
let res = client.post("/").body(r#"{ "foo": "bar" }"#).send().await;
|
||||||
@@ -253,7 +257,9 @@ mod tests {
|
|||||||
async fn valid_json_content_type(content_type: &str) -> bool {
|
async fn valid_json_content_type(content_type: &str) -> bool {
|
||||||
println!("testing {:?}", content_type);
|
println!("testing {:?}", content_type);
|
||||||
|
|
||||||
let app = Router::new().route("/", post(|Json(_): Json<Value>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/", post(|Json(_): Json<Value>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let res = TestClient::new(app)
|
let res = TestClient::new(app)
|
||||||
.post("/")
|
.post("/")
|
||||||
@@ -274,7 +280,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn invalid_json_syntax() {
|
async fn invalid_json_syntax() {
|
||||||
let app = Router::new().route("/", post(|_: Json<serde_json::Value>| async {}));
|
let app = Router::new()
|
||||||
|
.route("/", post(|_: Json<serde_json::Value>| async {}))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
let res = client
|
let res = client
|
||||||
|
|||||||
@@ -302,7 +302,8 @@ mod tests {
|
|||||||
|
|
||||||
async fn handler() {}
|
async fn handler() {}
|
||||||
|
|
||||||
let app = Router::new().route("/", get(handler.layer(from_extractor::<RequireAuth>())));
|
let app =
|
||||||
|
Router::with_state(()).route("/", get(handler.layer(from_extractor::<RequireAuth>())));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ mod tests {
|
|||||||
(&headers["x-axum-test"]).to_str().unwrap().to_owned()
|
(&headers["x-axum-test"]).to_str().unwrap().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::with_state(())
|
||||||
.route("/", get(handle))
|
.route("/", get(handle))
|
||||||
.layer(from_fn(insert_header));
|
.layer(from_fn(insert_header));
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Router::<Body>::new()
|
Router::<(), Body, _>::new()
|
||||||
.route("/", get(impl_trait_ok))
|
.route("/", get(impl_trait_ok))
|
||||||
.route("/", get(impl_trait_err))
|
.route("/", get(impl_trait_err))
|
||||||
.route("/", get(impl_trait_both))
|
.route("/", get(impl_trait_both))
|
||||||
@@ -203,7 +203,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Router::<Body>::new()
|
Router::<(), Body, _>::new()
|
||||||
.route("/", get(status))
|
.route("/", get(status))
|
||||||
.route("/", get(status_headermap))
|
.route("/", get(status_headermap))
|
||||||
.route("/", get(status_header_array))
|
.route("/", get(status_header_array))
|
||||||
|
|||||||
@@ -508,7 +508,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn basic() {
|
async fn basic() {
|
||||||
let app = Router::new().route(
|
let app = Router::with_state(()).route(
|
||||||
"/",
|
"/",
|
||||||
get(|| async {
|
get(|| async {
|
||||||
let stream = stream::iter(vec![
|
let stream = stream::iter(vec![
|
||||||
@@ -553,7 +553,7 @@ mod tests {
|
|||||||
async fn keep_alive() {
|
async fn keep_alive() {
|
||||||
const DELAY: Duration = Duration::from_secs(5);
|
const DELAY: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
let app = Router::new().route(
|
let app = Router::with_state(()).route(
|
||||||
"/",
|
"/",
|
||||||
get(|| async {
|
get(|| async {
|
||||||
let stream = stream::repeat_with(|| Event::default().data("msg"))
|
let stream = stream::repeat_with(|| Event::default().data("msg"))
|
||||||
@@ -589,7 +589,7 @@ mod tests {
|
|||||||
async fn keep_alive_ends_when_the_stream_ends() {
|
async fn keep_alive_ends_when_the_stream_ends() {
|
||||||
const DELAY: Duration = Duration::from_secs(5);
|
const DELAY: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
let app = Router::new().route(
|
let app = Router::with_state(()).route(
|
||||||
"/",
|
"/",
|
||||||
get(|| async {
|
get(|| async {
|
||||||
let stream = stream::repeat_with(|| Event::default().data("msg"))
|
let stream = stream::repeat_with(|| Event::default().data("msg"))
|
||||||
|
|||||||
@@ -1193,26 +1193,28 @@ mod tests {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn buiding_complex_router() {
|
fn buiding_complex_router() {
|
||||||
let app = crate::Router::new().route(
|
let app = crate::Router::new()
|
||||||
"/",
|
.route(
|
||||||
// use the all the things :bomb:
|
"/",
|
||||||
get(ok)
|
// use the all the things :bomb:
|
||||||
.post(ok)
|
get(ok)
|
||||||
.route_layer(RequireAuthorizationLayer::bearer("password"))
|
.post(ok)
|
||||||
.merge(
|
.route_layer(RequireAuthorizationLayer::bearer("password"))
|
||||||
delete_service(ServeDir::new("."))
|
.merge(
|
||||||
.handle_error(|_| async { StatusCode::NOT_FOUND }),
|
delete_service(ServeDir::new("."))
|
||||||
)
|
.handle_error(|_| async { StatusCode::NOT_FOUND }),
|
||||||
.fallback((|| async { StatusCode::NOT_FOUND }).into_service())
|
)
|
||||||
.put(ok)
|
.fallback((|| async { StatusCode::NOT_FOUND }).into_service())
|
||||||
.layer(
|
.put(ok)
|
||||||
ServiceBuilder::new()
|
.layer(
|
||||||
.layer(HandleErrorLayer::new(|_| async {
|
ServiceBuilder::new()
|
||||||
StatusCode::REQUEST_TIMEOUT
|
.layer(HandleErrorLayer::new(|_| async {
|
||||||
}))
|
StatusCode::REQUEST_TIMEOUT
|
||||||
.layer(TimeoutLayer::new(Duration::from_secs(10))),
|
}))
|
||||||
),
|
.layer(TimeoutLayer::new(Duration::from_secs(10))),
|
||||||
);
|
),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
crate::Server::bind(&"0.0.0.0:0".parse().unwrap()).serve(app.into_make_service());
|
crate::Server::bind(&"0.0.0.0:0".parse().unwrap()).serve(app.into_make_service());
|
||||||
}
|
}
|
||||||
|
|||||||
+100
-15
@@ -16,6 +16,7 @@ use std::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
fmt,
|
fmt,
|
||||||
|
marker::PhantomData,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
@@ -62,23 +63,33 @@ impl RouteId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The router type for composing handlers and services.
|
/// The router type for composing handlers and services.
|
||||||
pub struct Router<B = Body> {
|
pub struct Router<S, B = Body, R = MissingState> {
|
||||||
|
// Invariant: If `R == MissingState` then `state` is `None`
|
||||||
|
// If `R == WithState` then state is `Some`
|
||||||
|
// `R` cannot have other values
|
||||||
|
state: Option<S>,
|
||||||
routes: HashMap<RouteId, Endpoint<B>>,
|
routes: HashMap<RouteId, Endpoint<B>>,
|
||||||
node: Arc<Node>,
|
node: Arc<Node>,
|
||||||
fallback: Fallback<B>,
|
fallback: Fallback<B>,
|
||||||
|
_marker: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Clone for Router<B> {
|
impl<S, B, R> Clone for Router<S, B, R>
|
||||||
|
where
|
||||||
|
S: Clone,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
state: self.state.clone(),
|
||||||
routes: self.routes.clone(),
|
routes: self.routes.clone(),
|
||||||
node: Arc::clone(&self.node),
|
node: Arc::clone(&self.node),
|
||||||
fallback: self.fallback.clone(),
|
fallback: self.fallback.clone(),
|
||||||
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Default for Router<B>
|
impl<S, B> Default for Router<S, B, MissingState>
|
||||||
where
|
where
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
{
|
{
|
||||||
@@ -87,12 +98,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> fmt::Debug for Router<B> {
|
impl<S, B, R> fmt::Debug for Router<S, B, R>
|
||||||
|
where
|
||||||
|
S: fmt::Debug,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self {
|
||||||
|
state,
|
||||||
|
routes,
|
||||||
|
node,
|
||||||
|
fallback,
|
||||||
|
_marker,
|
||||||
|
} = self;
|
||||||
f.debug_struct("Router")
|
f.debug_struct("Router")
|
||||||
.field("routes", &self.routes)
|
.field("state", &state)
|
||||||
.field("node", &self.node)
|
.field("routes", &routes)
|
||||||
.field("fallback", &self.fallback)
|
.field("node", &node)
|
||||||
|
.field("fallback", &fallback)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,7 +122,7 @@ impl<B> fmt::Debug for Router<B> {
|
|||||||
pub(crate) const NEST_TAIL_PARAM: &str = "__private__axum_nest_tail_param";
|
pub(crate) const NEST_TAIL_PARAM: &str = "__private__axum_nest_tail_param";
|
||||||
const NEST_TAIL_PARAM_CAPTURE: &str = "/*__private__axum_nest_tail_param";
|
const NEST_TAIL_PARAM_CAPTURE: &str = "/*__private__axum_nest_tail_param";
|
||||||
|
|
||||||
impl<B> Router<B>
|
impl<S, B> Router<S, B, MissingState>
|
||||||
where
|
where
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
{
|
{
|
||||||
@@ -110,12 +132,42 @@ where
|
|||||||
/// all requests.
|
/// all requests.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
state: None,
|
||||||
routes: Default::default(),
|
routes: Default::default(),
|
||||||
node: Default::default(),
|
node: Default::default(),
|
||||||
fallback: Fallback::Default(Route::new(NotFound)),
|
fallback: Fallback::Default(Route::new(NotFound)),
|
||||||
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO(david): docs
|
||||||
|
pub fn state(self, state: S) -> Router<S, B, WithState> {
|
||||||
|
Router {
|
||||||
|
state: Some(state),
|
||||||
|
routes: self.routes,
|
||||||
|
node: self.node,
|
||||||
|
fallback: self.fallback,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> Router<S, B, WithState>
|
||||||
|
where
|
||||||
|
B: HttpBody + Send + 'static,
|
||||||
|
{
|
||||||
|
/// TODO(david): docs
|
||||||
|
pub fn with_state(state: S) -> Self {
|
||||||
|
Router::new().state(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B, R> Router<S, B, R>
|
||||||
|
where
|
||||||
|
B: HttpBody + Send + 'static,
|
||||||
|
S: 'static,
|
||||||
|
R: 'static,
|
||||||
|
{
|
||||||
#[doc = include_str!("../docs/routing/route.md")]
|
#[doc = include_str!("../docs/routing/route.md")]
|
||||||
pub fn route<T>(mut self, path: &str, service: T) -> Self
|
pub fn route<T>(mut self, path: &str, service: T) -> Self
|
||||||
where
|
where
|
||||||
@@ -128,7 +180,10 @@ where
|
|||||||
panic!("Paths must start with a `/`");
|
panic!("Paths must start with a `/`");
|
||||||
}
|
}
|
||||||
|
|
||||||
let service = match try_downcast::<Router<B>, _>(service) {
|
// Downcase to `WithState` rather than `R` because `Router<S, B, R>` only implements
|
||||||
|
// `Service` if `R == WithState` so any other type of `R` cannot be passed to `.router` in
|
||||||
|
// the first place
|
||||||
|
let service = match try_downcast::<Router<S, B, WithState>, _>(service) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
panic!("Invalid route: `Router::route` cannot be used with `Router`s. Use `Router::nest` instead")
|
panic!("Invalid route: `Router::route` cannot be used with `Router`s. Use `Router::nest` instead")
|
||||||
}
|
}
|
||||||
@@ -171,7 +226,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc = include_str!("../docs/routing/nest.md")]
|
#[doc = include_str!("../docs/routing/nest.md")]
|
||||||
pub fn nest(mut self, mut path: &str, router: Router<B>) -> Self {
|
pub fn nest(mut self, mut path: &str, router: Router<S, B, MissingState>) -> Self {
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
// nesting at `""` and `"/"` should mean the same thing
|
// nesting at `""` and `"/"` should mean the same thing
|
||||||
path = "/";
|
path = "/";
|
||||||
@@ -184,11 +239,15 @@ where
|
|||||||
let prefix = path;
|
let prefix = path;
|
||||||
|
|
||||||
let Router {
|
let Router {
|
||||||
|
state,
|
||||||
mut routes,
|
mut routes,
|
||||||
node,
|
node,
|
||||||
fallback,
|
fallback,
|
||||||
|
_marker: _,
|
||||||
} = router;
|
} = router;
|
||||||
|
|
||||||
|
debug_assert!(state.is_none());
|
||||||
|
|
||||||
if let Fallback::Custom(_) = fallback {
|
if let Fallback::Custom(_) = fallback {
|
||||||
panic!("Cannot nest `Router`s that has a fallback");
|
panic!("Cannot nest `Router`s that has a fallback");
|
||||||
}
|
}
|
||||||
@@ -255,16 +314,20 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc = include_str!("../docs/routing/merge.md")]
|
#[doc = include_str!("../docs/routing/merge.md")]
|
||||||
pub fn merge<R>(mut self, other: R) -> Self
|
pub fn merge<R2>(mut self, other: R2) -> Self
|
||||||
where
|
where
|
||||||
R: Into<Router<B>>,
|
R2: Into<Router<S, B, MissingState>>,
|
||||||
{
|
{
|
||||||
let Router {
|
let Router {
|
||||||
|
state,
|
||||||
routes,
|
routes,
|
||||||
node,
|
node,
|
||||||
fallback,
|
fallback,
|
||||||
|
_marker: _,
|
||||||
} = other.into();
|
} = other.into();
|
||||||
|
|
||||||
|
debug_assert!(state.is_none());
|
||||||
|
|
||||||
for (id, route) in routes {
|
for (id, route) in routes {
|
||||||
let path = node
|
let path = node
|
||||||
.route_id_to_path
|
.route_id_to_path
|
||||||
@@ -289,7 +352,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc = include_str!("../docs/routing/layer.md")]
|
#[doc = include_str!("../docs/routing/layer.md")]
|
||||||
pub fn layer<L, NewReqBody, NewResBody>(self, layer: L) -> Router<NewReqBody>
|
pub fn layer<L, NewReqBody, NewResBody>(self, layer: L) -> Router<S, NewReqBody, R>
|
||||||
where
|
where
|
||||||
L: Layer<Route<B>>,
|
L: Layer<Route<B>>,
|
||||||
L::Service:
|
L::Service:
|
||||||
@@ -322,9 +385,11 @@ where
|
|||||||
let fallback = self.fallback.map(|svc| Route::new(layer.layer(svc)));
|
let fallback = self.fallback.map(|svc| Route::new(layer.layer(svc)));
|
||||||
|
|
||||||
Router {
|
Router {
|
||||||
|
state: self.state,
|
||||||
routes,
|
routes,
|
||||||
node: self.node,
|
node: self.node,
|
||||||
fallback,
|
fallback,
|
||||||
|
_marker: self._marker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,9 +424,11 @@ where
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Router {
|
Router {
|
||||||
|
state: self.state,
|
||||||
routes,
|
routes,
|
||||||
node: self.node,
|
node: self.node,
|
||||||
fallback: self.fallback,
|
fallback: self.fallback,
|
||||||
|
_marker: self._marker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +473,13 @@ where
|
|||||||
pub fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C> {
|
pub fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C> {
|
||||||
IntoMakeServiceWithConnectInfo::new(self)
|
IntoMakeServiceWithConnectInfo::new(self)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> Router<S, B, WithState>
|
||||||
|
where
|
||||||
|
B: HttpBody + Send + 'static,
|
||||||
|
S: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn call_route(
|
fn call_route(
|
||||||
&self,
|
&self,
|
||||||
@@ -442,6 +515,10 @@ where
|
|||||||
|
|
||||||
url_params::insert_url_params(req.extensions_mut(), match_.params);
|
url_params::insert_url_params(req.extensions_mut(), match_.params);
|
||||||
|
|
||||||
|
// the `unwrap` is safe because `self.state` is always some if `R = WithState`, which it is
|
||||||
|
req.extensions_mut()
|
||||||
|
.insert(crate::extract::State(self.state.as_ref().unwrap().clone()));
|
||||||
|
|
||||||
let mut route = self
|
let mut route = self
|
||||||
.routes
|
.routes
|
||||||
.get(&id)
|
.get(&id)
|
||||||
@@ -455,9 +532,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Service<Request<B>> for Router<B>
|
impl<S, B> Service<Request<B>> for Router<S, B, WithState>
|
||||||
where
|
where
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
|
S: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Response = Response;
|
type Response = Response;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
@@ -496,6 +574,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum MissingState {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum WithState {}
|
||||||
|
|
||||||
/// Wrapper around `matchit::Router` that supports merging two `Router`s.
|
/// Wrapper around `matchit::Router` that supports merging two `Router`s.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
struct Node {
|
struct Node {
|
||||||
@@ -599,5 +683,6 @@ impl<B> fmt::Debug for Endpoint<B> {
|
|||||||
#[allow(warnings)]
|
#[allow(warnings)]
|
||||||
fn traits() {
|
fn traits() {
|
||||||
use crate::test_helpers::*;
|
use crate::test_helpers::*;
|
||||||
assert_send::<Router<()>>();
|
assert_send::<Router<(), (), WithState>>();
|
||||||
|
assert_send::<Router<(), (), MissingState>>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ use crate::handler::Handler;
|
|||||||
async fn basic() {
|
async fn basic() {
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/foo", get(|| async {}))
|
.route("/foo", get(|| async {}))
|
||||||
.fallback((|| async { "fallback" }).into_service());
|
.fallback((|| async { "fallback" }).into_service())
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -20,7 +21,8 @@ async fn basic() {
|
|||||||
async fn nest() {
|
async fn nest() {
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.nest("/foo", Router::new().route("/bar", get(|| async {})))
|
.nest("/foo", Router::new().route("/bar", get(|| async {})))
|
||||||
.fallback((|| async { "fallback" }).into_service());
|
.fallback((|| async { "fallback" }).into_service())
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -38,7 +40,8 @@ async fn or() {
|
|||||||
|
|
||||||
let app = one
|
let app = one
|
||||||
.merge(two)
|
.merge(two)
|
||||||
.fallback((|| async { "fallback" }).into_service());
|
.fallback((|| async { "fallback" }).into_service())
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,16 @@ mod for_handlers {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_handles_head() {
|
async fn get_handles_head() {
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/",
|
.route(
|
||||||
get(|| async {
|
"/",
|
||||||
let mut headers = HeaderMap::new();
|
get(|| async {
|
||||||
headers.insert("x-some-header", "foobar".parse().unwrap());
|
let mut headers = HeaderMap::new();
|
||||||
(headers, "you shouldn't see this")
|
headers.insert("x-some-header", "foobar".parse().unwrap());
|
||||||
}),
|
(headers, "you shouldn't see this")
|
||||||
);
|
}),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
// don't use reqwest because it always strips bodies from HEAD responses
|
// don't use reqwest because it always strips bodies from HEAD responses
|
||||||
let res = app
|
let res = app
|
||||||
@@ -43,14 +45,16 @@ mod for_services {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_handles_head() {
|
async fn get_handles_head() {
|
||||||
let app = Router::new().route(
|
let app = Router::new()
|
||||||
"/",
|
.route(
|
||||||
get_service(service_fn(|_req: Request<Body>| async move {
|
"/",
|
||||||
Ok::<_, Infallible>(
|
get_service(service_fn(|_req: Request<Body>| async move {
|
||||||
([("x-some-header", "foobar")], "you shouldn't see this").into_response(),
|
Ok::<_, Infallible>(
|
||||||
)
|
([("x-some-header", "foobar")], "you shouldn't see this").into_response(),
|
||||||
})),
|
)
|
||||||
);
|
})),
|
||||||
|
)
|
||||||
|
.state(());
|
||||||
|
|
||||||
// don't use reqwest because it always strips bodies from HEAD responses
|
// don't use reqwest because it always strips bodies from HEAD responses
|
||||||
let res = app
|
let res = app
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ impl<R> Service<R> for Svc {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn handler() {
|
async fn handler() {
|
||||||
let app = Router::new().route(
|
let app = Router::with_state(()).route(
|
||||||
"/",
|
"/",
|
||||||
get(forever.layer(
|
get(forever.layer(
|
||||||
ServiceBuilder::new()
|
ServiceBuilder::new()
|
||||||
@@ -50,7 +50,7 @@ async fn handler() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn handler_multiple_methods_first() {
|
async fn handler_multiple_methods_first() {
|
||||||
let app = Router::new().route(
|
let app = Router::with_state(()).route(
|
||||||
"/",
|
"/",
|
||||||
get(forever.layer(
|
get(forever.layer(
|
||||||
ServiceBuilder::new()
|
ServiceBuilder::new()
|
||||||
@@ -70,7 +70,7 @@ async fn handler_multiple_methods_first() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn handler_multiple_methods_middle() {
|
async fn handler_multiple_methods_middle() {
|
||||||
let app = Router::new().route(
|
let app = Router::with_state(()).route(
|
||||||
"/",
|
"/",
|
||||||
delete(unit)
|
delete(unit)
|
||||||
.get(
|
.get(
|
||||||
@@ -93,7 +93,7 @@ async fn handler_multiple_methods_middle() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn handler_multiple_methods_last() {
|
async fn handler_multiple_methods_last() {
|
||||||
let app = Router::new().route(
|
let app = Router::with_state(()).route(
|
||||||
"/",
|
"/",
|
||||||
delete(unit).get(
|
delete(unit).get(
|
||||||
forever.layer(
|
forever.layer(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ async fn basic() {
|
|||||||
.route("/foo", get(|| async {}))
|
.route("/foo", get(|| async {}))
|
||||||
.route("/bar", get(|| async {}));
|
.route("/bar", get(|| async {}));
|
||||||
let two = Router::new().route("/baz", get(|| async {}));
|
let two = Router::new().route("/baz", get(|| async {}));
|
||||||
let app = one.merge(two);
|
let app = one.merge(two).state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -41,7 +41,8 @@ async fn multiple_ors_balanced_differently() {
|
|||||||
one.clone()
|
one.clone()
|
||||||
.merge(two.clone())
|
.merge(two.clone())
|
||||||
.merge(three.clone())
|
.merge(three.clone())
|
||||||
.merge(four.clone()),
|
.merge(four.clone())
|
||||||
|
.state(()),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@@ -49,18 +50,20 @@ async fn multiple_ors_balanced_differently() {
|
|||||||
"two",
|
"two",
|
||||||
one.clone()
|
one.clone()
|
||||||
.merge(two.clone())
|
.merge(two.clone())
|
||||||
.merge(three.clone().merge(four.clone())),
|
.merge(three.clone().merge(four.clone()))
|
||||||
|
.state(()),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
test(
|
test(
|
||||||
"three",
|
"three",
|
||||||
one.clone()
|
one.clone()
|
||||||
.merge(two.clone().merge(three.clone()).merge(four.clone())),
|
.merge(two.clone().merge(three.clone()).merge(four.clone()))
|
||||||
|
.state(()),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
test("four", one.merge(two.merge(three.merge(four)))).await;
|
test("four", one.merge(two.merge(three.merge(four))).state(())).await;
|
||||||
|
|
||||||
async fn test<S, ResBody>(name: &str, app: S)
|
async fn test<S, ResBody>(name: &str, app: S)
|
||||||
where
|
where
|
||||||
@@ -89,11 +92,11 @@ async fn nested_or() {
|
|||||||
|
|
||||||
let bar_or_baz = bar.merge(baz);
|
let bar_or_baz = bar.merge(baz);
|
||||||
|
|
||||||
let client = TestClient::new(bar_or_baz.clone());
|
let client = TestClient::new(bar_or_baz.clone().state(()));
|
||||||
assert_eq!(client.get("/bar").send().await.text().await, "bar");
|
assert_eq!(client.get("/bar").send().await.text().await, "bar");
|
||||||
assert_eq!(client.get("/baz").send().await.text().await, "baz");
|
assert_eq!(client.get("/baz").send().await.text().await, "baz");
|
||||||
|
|
||||||
let client = TestClient::new(Router::new().nest("/foo", bar_or_baz));
|
let client = TestClient::new(Router::new().nest("/foo", bar_or_baz).state(()));
|
||||||
assert_eq!(client.get("/foo/bar").send().await.text().await, "bar");
|
assert_eq!(client.get("/foo/bar").send().await.text().await, "bar");
|
||||||
assert_eq!(client.get("/foo/baz").send().await.text().await, "baz");
|
assert_eq!(client.get("/foo/baz").send().await.text().await, "baz");
|
||||||
}
|
}
|
||||||
@@ -102,7 +105,10 @@ async fn nested_or() {
|
|||||||
async fn or_with_route_following() {
|
async fn or_with_route_following() {
|
||||||
let one = Router::new().route("/one", get(|| async { "one" }));
|
let one = Router::new().route("/one", get(|| async { "one" }));
|
||||||
let two = Router::new().route("/two", get(|| async { "two" }));
|
let two = Router::new().route("/two", get(|| async { "two" }));
|
||||||
let app = one.merge(two).route("/three", get(|| async { "three" }));
|
let app = one
|
||||||
|
.merge(two)
|
||||||
|
.route("/three", get(|| async { "three" }))
|
||||||
|
.state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -122,7 +128,7 @@ async fn layer() {
|
|||||||
let two = Router::new()
|
let two = Router::new()
|
||||||
.route("/bar", get(|| async {}))
|
.route("/bar", get(|| async {}))
|
||||||
.layer(ConcurrencyLimitLayer::new(10));
|
.layer(ConcurrencyLimitLayer::new(10));
|
||||||
let app = one.merge(two);
|
let app = one.merge(two).state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -145,7 +151,7 @@ async fn layer_and_handle_error() {
|
|||||||
}))
|
}))
|
||||||
.layer(TimeoutLayer::new(Duration::from_millis(10))),
|
.layer(TimeoutLayer::new(Duration::from_millis(10))),
|
||||||
);
|
);
|
||||||
let app = one.merge(two);
|
let app = one.merge(two).state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
@@ -159,7 +165,7 @@ async fn nesting() {
|
|||||||
let two = Router::new().nest("/bar", Router::new().route("/baz", get(|| async {})));
|
let two = Router::new().nest("/bar", Router::new().route("/baz", get(|| async {})));
|
||||||
let app = one.merge(two);
|
let app = one.merge(two);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/bar/baz").send().await;
|
let res = client.get("/bar/baz").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -171,7 +177,7 @@ async fn boxed() {
|
|||||||
let two = Router::new().route("/bar", get(|| async {}));
|
let two = Router::new().route("/bar", get(|| async {}));
|
||||||
let app = one.merge(two);
|
let app = one.merge(two);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/bar").send().await;
|
let res = client.get("/bar").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -188,7 +194,7 @@ async fn many_ors() {
|
|||||||
.merge(Router::new().route("/r6", get(|| async {})))
|
.merge(Router::new().route("/r6", get(|| async {})))
|
||||||
.merge(Router::new().route("/r7", get(|| async {})));
|
.merge(Router::new().route("/r7", get(|| async {})));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
for n in 1..=7 {
|
for n in 1..=7 {
|
||||||
let res = client.get(&format!("/r{}", n)).send().await;
|
let res = client.get(&format!("/r{}", n)).send().await;
|
||||||
@@ -217,7 +223,7 @@ async fn services() {
|
|||||||
})),
|
})),
|
||||||
));
|
));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo").send().await;
|
let res = client.get("/foo").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -243,7 +249,7 @@ async fn nesting_and_seeing_the_right_uri() {
|
|||||||
let one = Router::new().nest("/foo", Router::new().route("/bar", get(all_the_uris)));
|
let one = Router::new().nest("/foo", Router::new().route("/bar", get(all_the_uris)));
|
||||||
let two = Router::new().route("/foo", get(all_the_uris));
|
let two = Router::new().route("/foo", get(all_the_uris));
|
||||||
|
|
||||||
let client = TestClient::new(one.merge(two));
|
let client = TestClient::new(one.merge(two).state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/bar").send().await;
|
let res = client.get("/foo/bar").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -276,7 +282,7 @@ async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() {
|
|||||||
);
|
);
|
||||||
let two = Router::new().route("/foo", get(all_the_uris));
|
let two = Router::new().route("/foo", get(all_the_uris));
|
||||||
|
|
||||||
let client = TestClient::new(one.merge(two));
|
let client = TestClient::new(one.merge(two).state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/bar/baz").send().await;
|
let res = client.get("/foo/bar/baz").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -310,7 +316,7 @@ async fn nesting_and_seeing_the_right_uri_ors_with_nesting() {
|
|||||||
let two = Router::new().nest("/two", Router::new().route("/qux", get(all_the_uris)));
|
let two = Router::new().nest("/two", Router::new().route("/qux", get(all_the_uris)));
|
||||||
let three = Router::new().route("/three", get(all_the_uris));
|
let three = Router::new().route("/three", get(all_the_uris));
|
||||||
|
|
||||||
let client = TestClient::new(one.merge(two).merge(three));
|
let client = TestClient::new(one.merge(two).merge(three).state(()));
|
||||||
|
|
||||||
let res = client.get("/one/bar/baz").send().await;
|
let res = client.get("/one/bar/baz").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -354,7 +360,7 @@ async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() {
|
|||||||
);
|
);
|
||||||
let two = Router::new().route("/two/foo", get(all_the_uris));
|
let two = Router::new().route("/two/foo", get(all_the_uris));
|
||||||
|
|
||||||
let client = TestClient::new(one.merge(two));
|
let client = TestClient::new(one.merge(two).state(()));
|
||||||
|
|
||||||
let res = client.get("/one/foo/bar").send().await;
|
let res = client.get("/one/foo/bar").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -387,7 +393,7 @@ async fn middleware_that_return_early() {
|
|||||||
|
|
||||||
let public = Router::new().route("/public", get(|| async {}));
|
let public = Router::new().route("/public", get(|| async {}));
|
||||||
|
|
||||||
let client = TestClient::new(private.merge(public));
|
let client = TestClient::new(private.merge(public).state(()));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client.get("/").send().await.status(),
|
client.get("/").send().await.status(),
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ async fn hello_world() {
|
|||||||
.route("/", get(root).post(foo))
|
.route("/", get(root).post(foo))
|
||||||
.route("/users", post(users_create));
|
.route("/users", post(users_create));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
let body = res.text().await;
|
let body = res.text().await;
|
||||||
@@ -75,7 +75,7 @@ async fn routing() {
|
|||||||
get(|_: Request<Body>| async { "users#action" }),
|
get(|_: Request<Body>| async { "users#action" }),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
@@ -99,7 +99,7 @@ async fn routing() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn router_type_doesnt_change() {
|
async fn router_type_doesnt_change() {
|
||||||
let app: Router = Router::new()
|
let app: Router<()> = Router::new()
|
||||||
.route(
|
.route(
|
||||||
"/",
|
"/",
|
||||||
on(MethodFilter::GET, |_: Request<Body>| async {
|
on(MethodFilter::GET, |_: Request<Body>| async {
|
||||||
@@ -111,7 +111,7 @@ async fn router_type_doesnt_change() {
|
|||||||
)
|
)
|
||||||
.layer(tower_http::compression::CompressionLayer::new());
|
.layer(tower_http::compression::CompressionLayer::new());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -149,7 +149,7 @@ async fn routing_between_services() {
|
|||||||
)
|
)
|
||||||
.route("/two", on_service(MethodFilter::GET, handle.into_service()));
|
.route("/two", on_service(MethodFilter::GET, handle.into_service()));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/one").send().await;
|
let res = client.get("/one").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -187,7 +187,7 @@ async fn middleware_on_single_route() {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
let body = res.text().await;
|
let body = res.text().await;
|
||||||
@@ -203,7 +203,7 @@ async fn service_in_bottom() {
|
|||||||
|
|
||||||
let app = Router::new().route("/", get_service(service_fn(handler)));
|
let app = Router::new().route("/", get_service(service_fn(handler)));
|
||||||
|
|
||||||
TestClient::new(app);
|
TestClient::new(app.state(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -212,7 +212,7 @@ async fn wrong_method_handler() {
|
|||||||
.route("/", get(|| async {}).post(|| async {}))
|
.route("/", get(|| async {}).post(|| async {}))
|
||||||
.route("/foo", patch(|| async {}));
|
.route("/foo", patch(|| async {}));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.patch("/").send().await;
|
let res = client.patch("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||||
@@ -250,7 +250,7 @@ async fn wrong_method_service() {
|
|||||||
.route("/", get_service(Svc).post_service(Svc))
|
.route("/", get_service(Svc).post_service(Svc))
|
||||||
.route("/foo", patch_service(Svc));
|
.route("/foo", patch_service(Svc));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.patch("/").send().await;
|
let res = client.patch("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||||
@@ -273,7 +273,7 @@ async fn multiple_methods_for_one_handler() {
|
|||||||
|
|
||||||
let app = Router::new().route("/", on(MethodFilter::GET | MethodFilter::POST, root));
|
let app = Router::new().route("/", on(MethodFilter::GET | MethodFilter::POST, root));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -286,7 +286,7 @@ async fn multiple_methods_for_one_handler() {
|
|||||||
async fn wildcard_sees_whole_url() {
|
async fn wildcard_sees_whole_url() {
|
||||||
let app = Router::new().route("/api/*rest", get(|uri: Uri| async move { uri.to_string() }));
|
let app = Router::new().route("/api/*rest", get(|uri: Uri| async move { uri.to_string() }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/api/foo/bar").send().await;
|
let res = client.get("/api/foo/bar").send().await;
|
||||||
assert_eq!(res.text().await, "/api/foo/bar");
|
assert_eq!(res.text().await, "/api/foo/bar");
|
||||||
@@ -305,7 +305,7 @@ async fn middleware_applies_to_routes_above() {
|
|||||||
)
|
)
|
||||||
.route("/two", get(|| async {}));
|
.route("/two", get(|| async {}));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/one").send().await;
|
let res = client.get("/one").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
|
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
|
||||||
@@ -318,7 +318,7 @@ async fn middleware_applies_to_routes_above() {
|
|||||||
async fn not_found_for_extra_trailing_slash() {
|
async fn not_found_for_extra_trailing_slash() {
|
||||||
let app = Router::new().route("/foo", get(|| async {}));
|
let app = Router::new().route("/foo", get(|| async {}));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/").send().await;
|
let res = client.get("/foo/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
@@ -331,7 +331,7 @@ async fn not_found_for_extra_trailing_slash() {
|
|||||||
async fn not_found_for_missing_trailing_slash() {
|
async fn not_found_for_missing_trailing_slash() {
|
||||||
let app = Router::new().route("/foo/", get(|| async {}));
|
let app = Router::new().route("/foo/", get(|| async {}));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo").send().await;
|
let res = client.get("/foo").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
@@ -343,7 +343,7 @@ async fn with_and_without_trailing_slash() {
|
|||||||
.route("/foo", get(|| async { "without tsr" }))
|
.route("/foo", get(|| async { "without tsr" }))
|
||||||
.route("/foo/", get(|| async { "with tsr" }));
|
.route("/foo/", get(|| async { "with tsr" }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/").send().await;
|
let res = client.get("/foo/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -362,7 +362,7 @@ async fn wildcard_doesnt_match_just_trailing_slash() {
|
|||||||
get(|Path(path): Path<String>| async move { path }),
|
get(|Path(path): Path<String>| async move { path }),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/x").send().await;
|
let res = client.get("/x").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
@@ -384,7 +384,7 @@ async fn static_and_dynamic_paths() {
|
|||||||
)
|
)
|
||||||
.route("/foo", get(|| async { "static" }));
|
.route("/foo", get(|| async { "static" }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/bar").send().await;
|
let res = client.get("/bar").send().await;
|
||||||
assert_eq!(res.text().await, "dynamic: bar");
|
assert_eq!(res.text().await, "dynamic: bar");
|
||||||
@@ -397,7 +397,7 @@ async fn static_and_dynamic_paths() {
|
|||||||
#[should_panic(expected = "Paths must start with a `/`. Use \"/\" for root routes")]
|
#[should_panic(expected = "Paths must start with a `/`. Use \"/\" for root routes")]
|
||||||
async fn empty_route() {
|
async fn empty_route() {
|
||||||
let app = Router::new().route("", get(|| async {}));
|
let app = Router::new().route("", get(|| async {}));
|
||||||
TestClient::new(app);
|
TestClient::new(app.state(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -429,7 +429,7 @@ async fn middleware_still_run_for_unmatched_requests() {
|
|||||||
.route("/", get(|| async {}))
|
.route("/", get(|| async {}))
|
||||||
.layer(tower::layer::layer_fn(CountMiddleware));
|
.layer(tower::layer::layer_fn(CountMiddleware));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
assert_eq!(COUNT.load(Ordering::SeqCst), 0);
|
assert_eq!(COUNT.load(Ordering::SeqCst), 0);
|
||||||
|
|
||||||
@@ -445,7 +445,7 @@ async fn middleware_still_run_for_unmatched_requests() {
|
|||||||
expected = "Invalid route: `Router::route` cannot be used with `Router`s. Use `Router::nest` instead"
|
expected = "Invalid route: `Router::route` cannot be used with `Router`s. Use `Router::nest` instead"
|
||||||
)]
|
)]
|
||||||
async fn routing_to_router_panics() {
|
async fn routing_to_router_panics() {
|
||||||
TestClient::new(Router::new().route("/", Router::new()));
|
TestClient::new(Router::new().route("/", Router::new().state(())).state(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -454,7 +454,7 @@ async fn route_layer() {
|
|||||||
.route("/foo", get(|| async {}))
|
.route("/foo", get(|| async {}))
|
||||||
.route_layer(RequireAuthorizationLayer::bearer("password"));
|
.route_layer(RequireAuthorizationLayer::bearer("password"));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client
|
let res = client
|
||||||
.get("/foo")
|
.get("/foo")
|
||||||
@@ -482,7 +482,7 @@ async fn different_methods_added_in_different_routes() {
|
|||||||
.route("/", get(|| async { "GET" }))
|
.route("/", get(|| async { "GET" }))
|
||||||
.route("/", post(|| async { "POST" }));
|
.route("/", post(|| async { "POST" }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
let body = res.text().await;
|
let body = res.text().await;
|
||||||
@@ -505,7 +505,7 @@ async fn different_methods_added_in_different_routes_deeply_nested() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/bar/baz").send().await;
|
let res = client.get("/foo/bar/baz").send().await;
|
||||||
let body = res.text().await;
|
let body = res.text().await;
|
||||||
@@ -522,7 +522,7 @@ async fn merging_routers_with_fallbacks_panics() {
|
|||||||
async fn fallback() {}
|
async fn fallback() {}
|
||||||
let one = Router::new().fallback(fallback.into_service());
|
let one = Router::new().fallback(fallback.into_service());
|
||||||
let two = Router::new().fallback(fallback.into_service());
|
let two = Router::new().fallback(fallback.into_service());
|
||||||
TestClient::new(one.merge(two));
|
TestClient::new(one.merge(two).state(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -531,7 +531,7 @@ async fn nesting_router_with_fallbacks_panics() {
|
|||||||
async fn fallback() {}
|
async fn fallback() {}
|
||||||
let one = Router::new().fallback(fallback.into_service());
|
let one = Router::new().fallback(fallback.into_service());
|
||||||
let app = Router::new().nest("/", one);
|
let app = Router::new().nest("/", one);
|
||||||
TestClient::new(app);
|
TestClient::new(app.state(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -539,7 +539,7 @@ async fn merging_routers_with_same_paths_but_different_methods() {
|
|||||||
let one = Router::new().route("/", get(|| async { "GET" }));
|
let one = Router::new().route("/", get(|| async { "GET" }));
|
||||||
let two = Router::new().route("/", post(|| async { "POST" }));
|
let two = Router::new().route("/", post(|| async { "POST" }));
|
||||||
|
|
||||||
let client = TestClient::new(one.merge(two));
|
let client = TestClient::new(one.merge(two).state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
let body = res.text().await;
|
let body = res.text().await;
|
||||||
@@ -556,7 +556,7 @@ async fn head_content_length_through_hyper_server() {
|
|||||||
.route("/", get(|| async { "foo" }))
|
.route("/", get(|| async { "foo" }))
|
||||||
.route("/json", get(|| async { Json(json!({ "foo": 1 })) }));
|
.route("/json", get(|| async { Json(json!({ "foo": 1 })) }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.head("/").send().await;
|
let res = client.head("/").send().await;
|
||||||
assert_eq!(res.headers()["content-length"], "3");
|
assert_eq!(res.headers()["content-length"], "3");
|
||||||
@@ -571,7 +571,7 @@ async fn head_content_length_through_hyper_server() {
|
|||||||
async fn head_content_length_through_hyper_server_that_hits_fallback() {
|
async fn head_content_length_through_hyper_server_that_hits_fallback() {
|
||||||
let app = Router::new().fallback((|| async { "foo" }).into_service());
|
let app = Router::new().fallback((|| async { "foo" }).into_service());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.head("/").send().await;
|
let res = client.head("/").send().await;
|
||||||
assert_eq!(res.headers()["content-length"], "3");
|
assert_eq!(res.headers()["content-length"], "3");
|
||||||
@@ -585,7 +585,7 @@ async fn head_with_middleware_applied() {
|
|||||||
.route("/", get(|| async { "Hello, World!" }))
|
.route("/", get(|| async { "Hello, World!" }))
|
||||||
.layer(CompressionLayer::new().compress_when(SizeAbove::new(0)));
|
.layer(CompressionLayer::new().compress_when(SizeAbove::new(0)));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
// send GET request
|
// send GET request
|
||||||
let res = client
|
let res = client
|
||||||
@@ -614,7 +614,7 @@ async fn head_with_middleware_applied() {
|
|||||||
#[should_panic(expected = "Paths must start with a `/`")]
|
#[should_panic(expected = "Paths must start with a `/`")]
|
||||||
async fn routes_must_start_with_slash() {
|
async fn routes_must_start_with_slash() {
|
||||||
let app = Router::new().route(":foo", get(|| async {}));
|
let app = Router::new().route(":foo", get(|| async {}));
|
||||||
TestClient::new(app);
|
TestClient::new(app.state(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -630,7 +630,7 @@ async fn limited_body_with_content_length() {
|
|||||||
)
|
)
|
||||||
.layer(RequestBodyLimitLayer::new(LIMIT));
|
.layer(RequestBodyLimitLayer::new(LIMIT));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.post("/").body("a".repeat(LIMIT)).send().await;
|
let res = client.post("/").body("a".repeat(LIMIT)).send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -652,7 +652,7 @@ async fn limited_body_with_streaming_body() {
|
|||||||
)
|
)
|
||||||
.layer(RequestBodyLimitLayer::new(LIMIT));
|
.layer(RequestBodyLimitLayer::new(LIMIT));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let stream = futures_util::stream::iter(vec![Ok::<_, hyper::Error>("a".repeat(LIMIT))]);
|
let stream = futures_util::stream::iter(vec![Ok::<_, hyper::Error>("a".repeat(LIMIT))]);
|
||||||
let res = client
|
let res = client
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ async fn nesting_apps() {
|
|||||||
.route("/", get(|| async { "hi" }))
|
.route("/", get(|| async { "hi" }))
|
||||||
.nest("/:version/api", api_routes);
|
.nest("/:version/api", api_routes);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -64,7 +64,7 @@ async fn wrong_method_nest() {
|
|||||||
let nested_app = Router::new().route("/", get(|| async {}));
|
let nested_app = Router::new().route("/", get(|| async {}));
|
||||||
let app = Router::new().nest("/", nested_app);
|
let app = Router::new().nest("/", nested_app);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -81,7 +81,7 @@ async fn nesting_router_at_root() {
|
|||||||
let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
|
let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
|
||||||
let app = Router::new().nest("/", nested);
|
let app = Router::new().nest("/", nested);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
@@ -99,7 +99,7 @@ async fn nesting_router_at_empty_path() {
|
|||||||
let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
|
let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
|
||||||
let app = Router::new().nest("", nested);
|
let app = Router::new().nest("", nested);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
@@ -116,7 +116,7 @@ async fn nesting_router_at_empty_path() {
|
|||||||
async fn nesting_handler_at_root() {
|
async fn nesting_handler_at_root() {
|
||||||
let app = Router::new().nest_service("/", get(|uri: Uri| async move { uri.to_string() }));
|
let app = Router::new().nest_service("/", get(|uri: Uri| async move { uri.to_string() }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/").send().await;
|
let res = client.get("/").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -146,7 +146,7 @@ async fn nested_url_extractor() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/bar/baz").send().await;
|
let res = client.get("/foo/bar/baz").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -170,7 +170,7 @@ async fn nested_url_original_extractor() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/bar/baz").send().await;
|
let res = client.get("/foo/bar/baz").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -193,7 +193,7 @@ async fn nested_service_sees_stripped_uri() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/bar/baz").send().await;
|
let res = client.get("/foo/bar/baz").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -212,7 +212,7 @@ async fn nest_static_file_server() {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/static/README.md").send().await;
|
let res = client.get("/static/README.md").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -229,7 +229,7 @@ async fn nested_multiple_routes() {
|
|||||||
)
|
)
|
||||||
.route("/", get(|| async { "root" }));
|
.route("/", get(|| async { "root" }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
assert_eq!(client.get("/").send().await.text().await, "root");
|
assert_eq!(client.get("/").send().await.text().await, "root");
|
||||||
assert_eq!(client.get("/api/users").send().await.text().await, "users");
|
assert_eq!(client.get("/api/users").send().await.text().await, "users");
|
||||||
@@ -245,7 +245,7 @@ async fn nested_with_other_route_also_matching_with_route_first() {
|
|||||||
.route("/teams", get(|| async { "teams" })),
|
.route("/teams", get(|| async { "teams" })),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
assert_eq!(client.get("/api").send().await.text().await, "api");
|
assert_eq!(client.get("/api").send().await.text().await, "api");
|
||||||
assert_eq!(client.get("/api/users").send().await.text().await, "users");
|
assert_eq!(client.get("/api/users").send().await.text().await, "users");
|
||||||
@@ -263,7 +263,7 @@ async fn nested_with_other_route_also_matching_with_route_last() {
|
|||||||
)
|
)
|
||||||
.route("/api", get(|| async { "api" }));
|
.route("/api", get(|| async { "api" }));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
assert_eq!(client.get("/api").send().await.text().await, "api");
|
assert_eq!(client.get("/api").send().await.text().await, "api");
|
||||||
assert_eq!(client.get("/api/users").send().await.text().await, "users");
|
assert_eq!(client.get("/api/users").send().await.text().await, "users");
|
||||||
@@ -282,7 +282,7 @@ async fn multiple_top_level_nests() {
|
|||||||
Router::new().route("/route", get(|| async { "two" })),
|
Router::new().route("/route", get(|| async { "two" })),
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
assert_eq!(client.get("/one/route").send().await.text().await, "one");
|
assert_eq!(client.get("/one/route").send().await.text().await, "one");
|
||||||
assert_eq!(client.get("/two/route").send().await.text().await, "two");
|
assert_eq!(client.get("/two/route").send().await.text().await, "two");
|
||||||
@@ -291,7 +291,7 @@ async fn multiple_top_level_nests() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
|
#[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
|
||||||
async fn nest_cannot_contain_wildcards() {
|
async fn nest_cannot_contain_wildcards() {
|
||||||
Router::<Body>::new().nest("/one/*rest", Router::new());
|
Router::<(), Body, _>::new().nest("/one/*rest", Router::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -333,7 +333,7 @@ async fn outer_middleware_still_see_whole_url() {
|
|||||||
.fallback(handler.into_service())
|
.fallback(handler.into_service())
|
||||||
.layer(tower::layer::layer_fn(SetUriExtension));
|
.layer(tower::layer::layer_fn(SetUriExtension));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
assert_eq!(client.get("/").send().await.text().await, "/");
|
assert_eq!(client.get("/").send().await.text().await, "/");
|
||||||
assert_eq!(client.get("/foo").send().await.text().await, "/foo");
|
assert_eq!(client.get("/foo").send().await.text().await, "/foo");
|
||||||
@@ -352,11 +352,12 @@ async fn nest_at_capture() {
|
|||||||
"/:b",
|
"/:b",
|
||||||
get(|Path((a, b)): Path<(String, String)>| async move { format!("a={} b={}", a, b) }),
|
get(|Path((a, b)): Path<(String, String)>| async move { format!("a={} b={}", a, b) }),
|
||||||
)
|
)
|
||||||
|
.state(())
|
||||||
.boxed_clone();
|
.boxed_clone();
|
||||||
|
|
||||||
let app = Router::new().nest_service("/:a", api_routes);
|
let app = Router::new().nest_service("/:a", api_routes);
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo/bar").send().await;
|
let res = client.get("/foo/bar").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -367,7 +368,7 @@ async fn nest_at_capture() {
|
|||||||
async fn nest_with_and_without_trailing() {
|
async fn nest_with_and_without_trailing() {
|
||||||
let app = Router::new().nest_service("/foo", get(|| async {}));
|
let app = Router::new().nest_service("/foo", get(|| async {}));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
|
|
||||||
let res = client.get("/foo").send().await;
|
let res = client.get("/foo").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
@@ -393,14 +394,14 @@ macro_rules! nested_route_test {
|
|||||||
async fn $name() {
|
async fn $name() {
|
||||||
let inner = Router::new().route($route_path, get(|| async {}));
|
let inner = Router::new().route($route_path, get(|| async {}));
|
||||||
let app = Router::new().nest($nested_path, inner);
|
let app = Router::new().nest($nested_path, inner);
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
let res = client.get($expected_path).send().await;
|
let res = client.get($expected_path).send().await;
|
||||||
let status = res.status();
|
let status = res.status();
|
||||||
assert_eq!(status, StatusCode::OK, "Router");
|
assert_eq!(status, StatusCode::OK, "Router");
|
||||||
|
|
||||||
let inner = Router::new().route($route_path, get(|| async {}));
|
let inner = Router::new().route($route_path, get(|| async {})).state(());
|
||||||
let app = Router::new().nest_service($nested_path, inner);
|
let app = Router::new().nest_service($nested_path, inner);
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app.state(()));
|
||||||
let res = client.get(dbg!($expected_path)).send().await;
|
let res = client.get(dbg!($expected_path)).send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK, "opaque");
|
assert_eq!(res.status(), StatusCode::OK, "opaque");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ mod tests {
|
|||||||
user_agent.to_string()
|
user_agent.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Router::new().route("/", get(handle));
|
let app = Router::new().route("/", get(handle)).state(());
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user