mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-27 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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"))
|
||||
}
|
||||
|
||||
let app = Router::<Body>::new()
|
||||
let app = Router::<_, Body, _>::new()
|
||||
.route("/set", get(set_cookie))
|
||||
.route("/get", get(get_cookie))
|
||||
.route("/remove", get(remove_cookie))
|
||||
.layer(Extension(Key::generate()))
|
||||
.layer(Extension(CustomKey(Key::generate())));
|
||||
.layer(Extension(CustomKey(Key::generate())))
|
||||
.state(());
|
||||
|
||||
let res = app
|
||||
.clone()
|
||||
@@ -294,9 +295,10 @@ mod tests {
|
||||
format!("{:?}", jar.get("key"))
|
||||
}
|
||||
|
||||
let app = Router::<Body>::new()
|
||||
let app = Router::<_, Body, _>::new()
|
||||
.route("/get", get(get_cookie))
|
||||
.layer(Extension(Key::generate()));
|
||||
.layer(Extension(Key::generate()))
|
||||
.state(());
|
||||
|
||||
let res = app
|
||||
.clone()
|
||||
|
||||
@@ -116,10 +116,12 @@ mod tests {
|
||||
values: Vec<String>,
|
||||
}
|
||||
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
post(|Form(data): Form<Data>| async move { data.values.join(",") }),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
post(|Form(data): Form<Data>| async move { data.values.join(",") }),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
@@ -97,10 +97,12 @@ mod tests {
|
||||
values: Vec<String>,
|
||||
}
|
||||
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
post(|Query(data): Query<Data>| async move { data.values.join(",") }),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
post(|Query(data): Query<Data>| async move { data.values.join(",") }),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
@@ -217,22 +217,24 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn extractor() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
post(|mut stream: JsonLines<User>| async move {
|
||||
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 1 });
|
||||
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 2 });
|
||||
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 3 });
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
post(|mut stream: JsonLines<User>| async move {
|
||||
assert_eq!(stream.next().await.unwrap().unwrap(), User { id: 1 });
|
||||
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`
|
||||
let err = stream.next().await.unwrap().unwrap_err();
|
||||
let _: &serde_json::Error = err
|
||||
.source()
|
||||
.unwrap()
|
||||
.downcast_ref::<serde_json::Error>()
|
||||
.unwrap();
|
||||
}),
|
||||
);
|
||||
// sources are downcastable to `serde_json::Error`
|
||||
let err = stream.next().await.unwrap().unwrap_err();
|
||||
let _: &serde_json::Error = err
|
||||
.source()
|
||||
.unwrap()
|
||||
.downcast_ref::<serde_json::Error>()
|
||||
.unwrap();
|
||||
}),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -255,17 +257,19 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn response() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
get(|| async {
|
||||
let values = futures_util::stream::iter(vec![
|
||||
Ok::<_, Infallible>(User { id: 1 }),
|
||||
Ok::<_, Infallible>(User { id: 2 }),
|
||||
Ok::<_, Infallible>(User { id: 3 }),
|
||||
]);
|
||||
JsonLines::new(values)
|
||||
}),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
get(|| async {
|
||||
let values = futures_util::stream::iter(vec![
|
||||
Ok::<_, Infallible>(User { id: 1 }),
|
||||
Ok::<_, Infallible>(User { id: 2 }),
|
||||
Ok::<_, Infallible>(User { id: 3 }),
|
||||
]);
|
||||
JsonLines::new(values)
|
||||
}),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ pub use self::typed::{FirstElementIs, TypedPath};
|
||||
pub use self::spa::SpaRouter;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// 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;
|
||||
}
|
||||
|
||||
impl<B> RouterExt<B> for Router<B>
|
||||
impl<S, B, R> RouterExt<S, B, R> for Router<S, B, R>
|
||||
where
|
||||
B: axum::body::HttpBody + Send + 'static,
|
||||
R: 'static,
|
||||
S: 'static,
|
||||
{
|
||||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_get<H, T, P>(self, handler: H) -> Self
|
||||
@@ -276,7 +278,7 @@ where
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
impl<B> Sealed for axum::Router<B> {}
|
||||
impl<S, B, R> Sealed for axum::Router<S, B, R> {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -289,7 +291,8 @@ mod tests {
|
||||
async fn test_tsr() {
|
||||
let app = Router::new()
|
||||
.route_with_tsr("/foo", get(|| async {}))
|
||||
.route_with_tsr("/bar/", get(|| async {}));
|
||||
.route_with_tsr("/bar/", get(|| async {}))
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ use axum::{
|
||||
handler::Handler,
|
||||
http::Request,
|
||||
response::Response,
|
||||
routing::{delete, get, on, post, MethodFilter},
|
||||
routing::{delete, get, on, post, MethodFilter, MissingState, WithState},
|
||||
Router,
|
||||
};
|
||||
use std::convert::Infallible;
|
||||
use std::{convert::Infallible, fmt};
|
||||
use tower_service::Service;
|
||||
|
||||
/// 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 _: Router<axum::body::Body> = app;
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct Resource<B = Body> {
|
||||
pub struct Resource<S, B = Body, R = MissingState> {
|
||||
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
|
||||
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}`.
|
||||
pub fn index<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
@@ -140,7 +169,7 @@ where
|
||||
/// Nest another router at the "member level".
|
||||
///
|
||||
/// 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();
|
||||
self.router = self.router.nest(&path, router);
|
||||
self
|
||||
@@ -149,7 +178,7 @@ where
|
||||
/// Nest another router at the "collection level".
|
||||
///
|
||||
/// 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();
|
||||
self.router = self.router.nest(&path, router);
|
||||
self
|
||||
@@ -173,8 +202,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> From<Resource<B>> for Router<B> {
|
||||
fn from(resource: Resource<B>) -> Self {
|
||||
impl<S, B> From<Resource<S, B, MissingState>> for Router<S, B, MissingState> {
|
||||
fn from(resource: Resource<S, B, MissingState>) -> Self {
|
||||
resource.router
|
||||
}
|
||||
}
|
||||
@@ -204,7 +233,7 @@ mod tests {
|
||||
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!(
|
||||
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
|
||||
.ready()
|
||||
.await
|
||||
|
||||
@@ -2,7 +2,7 @@ use axum::{
|
||||
body::{Body, HttpBody},
|
||||
error_handling::HandleError,
|
||||
response::Response,
|
||||
routing::{get_service, Route},
|
||||
routing::{get_service, MissingState, Route},
|
||||
Router,
|
||||
};
|
||||
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
|
||||
F: Clone + Send + 'static,
|
||||
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,
|
||||
B: HttpBody + Send + 'static,
|
||||
T: 'static,
|
||||
S: 'static,
|
||||
{
|
||||
fn from(spa: SpaRouter<B, T, F>) -> Self {
|
||||
let assets_service = get_service(ServeDir::new(&spa.paths.assets_dir))
|
||||
@@ -214,7 +215,8 @@ mod tests {
|
||||
async fn basic() {
|
||||
let app = Router::new()
|
||||
.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 res = client.get("/").send().await;
|
||||
@@ -239,8 +241,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn setting_index_file() {
|
||||
let app =
|
||||
Router::new().merge(SpaRouter::new("/assets", "test_files").index_file("index_2.html"));
|
||||
let app = Router::new()
|
||||
.merge(SpaRouter::new("/assets", "test_files").index_file("index_2.html"))
|
||||
.state(());
|
||||
let client = TestClient::new(app);
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
@@ -264,6 +267,6 @@ mod tests {
|
||||
|
||||
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();
|
||||
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)
|
||||
.unwrap()
|
||||
.serve(app.into_make_service_with_connect_info::<SocketAddr>());
|
||||
@@ -198,7 +198,7 @@ mod tests {
|
||||
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
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)
|
||||
.unwrap()
|
||||
.serve(app.into_make_service_with_connect_info::<MyConnectInfo>());
|
||||
|
||||
@@ -115,10 +115,12 @@ mod tests {
|
||||
|
||||
const LIMIT: u64 = 8;
|
||||
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
post(|_body: ContentLengthLimit<Bytes, LIMIT>| async {}),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
post(|_body: ContentLengthLimit<Bytes, LIMIT>| async {}),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let res = client
|
||||
@@ -154,7 +156,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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);
|
||||
|
||||
@@ -164,7 +168,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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);
|
||||
|
||||
@@ -179,7 +185,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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);
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ mod tests {
|
||||
host
|
||||
}
|
||||
|
||||
TestClient::new(Router::new().route("/", get(host_as_body)))
|
||||
TestClient::new(Router::new().route("/", get(host_as_body)).state(()))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -150,7 +150,8 @@ mod tests {
|
||||
Router::new().route("/assets/*path", get(handler)),
|
||||
)
|
||||
.nest_service("/foo", handler.into_service())
|
||||
.layer(tower::layer::layer_fn(SetMatchedPathExtension));
|
||||
.layer(tower::layer::layer_fn(SetMatchedPathExtension))
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -181,13 +182,17 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn nested_opaque_routers_append_to_matched_path() {
|
||||
let app = Router::new().nest_service(
|
||||
"/:a",
|
||||
Router::new().route(
|
||||
"/:b",
|
||||
get(|path: MatchedPath| async move { path.as_str().to_owned() }),
|
||||
),
|
||||
);
|
||||
let app = Router::new()
|
||||
.nest_service(
|
||||
"/:a",
|
||||
Router::new()
|
||||
.route(
|
||||
"/:b",
|
||||
get(|path: MatchedPath| async move { path.as_str().to_owned() }),
|
||||
)
|
||||
.state(()),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ mod raw_query;
|
||||
mod request_parts;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use axum_core::extract::{FromRequest, RequestParts};
|
||||
pub use axum_core::extract::{FromRequest, RequestParts, State};
|
||||
|
||||
#[doc(inline)]
|
||||
#[allow(deprecated)]
|
||||
@@ -103,7 +103,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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 res = client.get("/").body("foo").send().await;
|
||||
|
||||
@@ -257,7 +257,7 @@ mod tests {
|
||||
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);
|
||||
|
||||
|
||||
@@ -418,15 +418,17 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn extracting_url_params() {
|
||||
let app = Router::new().route(
|
||||
"/users/:id",
|
||||
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);
|
||||
}),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/users/:id",
|
||||
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);
|
||||
}),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -439,7 +441,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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);
|
||||
|
||||
@@ -449,10 +453,12 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn percent_decoding() {
|
||||
let app = Router::new().route(
|
||||
"/:key",
|
||||
get(|Path(param): Path<String>| async move { param }),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/:key",
|
||||
get(|Path(param): Path<String>| async move { param }),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -471,7 +477,8 @@ mod tests {
|
||||
.route(
|
||||
"/u/:key",
|
||||
get(|Path(param): Path<u128>| async move { param.to_string() }),
|
||||
);
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -494,7 +501,8 @@ mod tests {
|
||||
get(|Path(params): Path<HashMap<String, String>>| async move {
|
||||
params.get("rest").unwrap().clone()
|
||||
}),
|
||||
);
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -507,7 +515,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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);
|
||||
|
||||
@@ -520,7 +528,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -559,7 +571,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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);
|
||||
|
||||
@@ -574,18 +588,20 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn deserialize_into_vec_of_tuples() {
|
||||
let app = Router::new().route(
|
||||
"/:a/:b",
|
||||
get(|Path(params): Path<Vec<(String, String)>>| async move {
|
||||
assert_eq!(
|
||||
params,
|
||||
vec![
|
||||
("a".to_owned(), "foo".to_owned()),
|
||||
("b".to_owned(), "bar".to_owned())
|
||||
]
|
||||
);
|
||||
}),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/:a/:b",
|
||||
get(|Path(params): Path<Vec<(String, String)>>| async move {
|
||||
assert_eq!(
|
||||
params,
|
||||
vec![
|
||||
("a".to_owned(), "foo".to_owned()),
|
||||
("b".to_owned(), "bar".to_owned())
|
||||
]
|
||||
);
|
||||
}),
|
||||
)
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ mod tests {
|
||||
async fn multiple_request_extractors() {
|
||||
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);
|
||||
|
||||
@@ -248,7 +248,12 @@ mod tests {
|
||||
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;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -263,7 +268,7 @@ mod tests {
|
||||
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;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
+12
-4
@@ -221,7 +221,9 @@ mod tests {
|
||||
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 res = client.post("/").json(&json!({ "foo": "bar" })).send().await;
|
||||
@@ -237,7 +239,9 @@ mod tests {
|
||||
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 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 {
|
||||
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)
|
||||
.post("/")
|
||||
@@ -274,7 +280,9 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
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 res = client
|
||||
|
||||
@@ -302,7 +302,8 @@ mod tests {
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ mod tests {
|
||||
(&headers["x-axum-test"]).to_str().unwrap().to_owned()
|
||||
}
|
||||
|
||||
let app = Router::new()
|
||||
let app = Router::with_state(())
|
||||
.route("/", get(handle))
|
||||
.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_err))
|
||||
.route("/", get(impl_trait_both))
|
||||
@@ -203,7 +203,7 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
Router::<Body>::new()
|
||||
Router::<(), Body, _>::new()
|
||||
.route("/", get(status))
|
||||
.route("/", get(status_headermap))
|
||||
.route("/", get(status_header_array))
|
||||
|
||||
@@ -508,7 +508,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn basic() {
|
||||
let app = Router::new().route(
|
||||
let app = Router::with_state(()).route(
|
||||
"/",
|
||||
get(|| async {
|
||||
let stream = stream::iter(vec![
|
||||
@@ -553,7 +553,7 @@ mod tests {
|
||||
async fn keep_alive() {
|
||||
const DELAY: Duration = Duration::from_secs(5);
|
||||
|
||||
let app = Router::new().route(
|
||||
let app = Router::with_state(()).route(
|
||||
"/",
|
||||
get(|| async {
|
||||
let stream = stream::repeat_with(|| Event::default().data("msg"))
|
||||
@@ -589,7 +589,7 @@ mod tests {
|
||||
async fn keep_alive_ends_when_the_stream_ends() {
|
||||
const DELAY: Duration = Duration::from_secs(5);
|
||||
|
||||
let app = Router::new().route(
|
||||
let app = Router::with_state(()).route(
|
||||
"/",
|
||||
get(|| async {
|
||||
let stream = stream::repeat_with(|| Event::default().data("msg"))
|
||||
|
||||
@@ -1193,26 +1193,28 @@ mod tests {
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn buiding_complex_router() {
|
||||
let app = crate::Router::new().route(
|
||||
"/",
|
||||
// use the all the things :bomb:
|
||||
get(ok)
|
||||
.post(ok)
|
||||
.route_layer(RequireAuthorizationLayer::bearer("password"))
|
||||
.merge(
|
||||
delete_service(ServeDir::new("."))
|
||||
.handle_error(|_| async { StatusCode::NOT_FOUND }),
|
||||
)
|
||||
.fallback((|| async { StatusCode::NOT_FOUND }).into_service())
|
||||
.put(ok)
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(HandleErrorLayer::new(|_| async {
|
||||
StatusCode::REQUEST_TIMEOUT
|
||||
}))
|
||||
.layer(TimeoutLayer::new(Duration::from_secs(10))),
|
||||
),
|
||||
);
|
||||
let app = crate::Router::new()
|
||||
.route(
|
||||
"/",
|
||||
// use the all the things :bomb:
|
||||
get(ok)
|
||||
.post(ok)
|
||||
.route_layer(RequireAuthorizationLayer::bearer("password"))
|
||||
.merge(
|
||||
delete_service(ServeDir::new("."))
|
||||
.handle_error(|_| async { StatusCode::NOT_FOUND }),
|
||||
)
|
||||
.fallback((|| async { StatusCode::NOT_FOUND }).into_service())
|
||||
.put(ok)
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
.layer(HandleErrorLayer::new(|_| async {
|
||||
StatusCode::REQUEST_TIMEOUT
|
||||
}))
|
||||
.layer(TimeoutLayer::new(Duration::from_secs(10))),
|
||||
),
|
||||
)
|
||||
.state(());
|
||||
|
||||
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,
|
||||
convert::Infallible,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
@@ -62,23 +63,33 @@ impl RouteId {
|
||||
}
|
||||
|
||||
/// 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>>,
|
||||
node: Arc<Node>,
|
||||
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 {
|
||||
Self {
|
||||
state: self.state.clone(),
|
||||
routes: self.routes.clone(),
|
||||
node: Arc::clone(&self.node),
|
||||
fallback: self.fallback.clone(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Default for Router<B>
|
||||
impl<S, B> Default for Router<S, B, MissingState>
|
||||
where
|
||||
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 {
|
||||
let Self {
|
||||
state,
|
||||
routes,
|
||||
node,
|
||||
fallback,
|
||||
_marker,
|
||||
} = self;
|
||||
f.debug_struct("Router")
|
||||
.field("routes", &self.routes)
|
||||
.field("node", &self.node)
|
||||
.field("fallback", &self.fallback)
|
||||
.field("state", &state)
|
||||
.field("routes", &routes)
|
||||
.field("node", &node)
|
||||
.field("fallback", &fallback)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -100,7 +122,7 @@ impl<B> fmt::Debug for Router<B> {
|
||||
pub(crate) const NEST_TAIL_PARAM: &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
|
||||
B: HttpBody + Send + 'static,
|
||||
{
|
||||
@@ -110,12 +132,42 @@ where
|
||||
/// all requests.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: None,
|
||||
routes: Default::default(),
|
||||
node: Default::default(),
|
||||
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")]
|
||||
pub fn route<T>(mut self, path: &str, service: T) -> Self
|
||||
where
|
||||
@@ -128,7 +180,10 @@ where
|
||||
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(_) => {
|
||||
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")]
|
||||
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() {
|
||||
// nesting at `""` and `"/"` should mean the same thing
|
||||
path = "/";
|
||||
@@ -184,11 +239,15 @@ where
|
||||
let prefix = path;
|
||||
|
||||
let Router {
|
||||
state,
|
||||
mut routes,
|
||||
node,
|
||||
fallback,
|
||||
_marker: _,
|
||||
} = router;
|
||||
|
||||
debug_assert!(state.is_none());
|
||||
|
||||
if let Fallback::Custom(_) = fallback {
|
||||
panic!("Cannot nest `Router`s that has a fallback");
|
||||
}
|
||||
@@ -255,16 +314,20 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
R: Into<Router<B>>,
|
||||
R2: Into<Router<S, B, MissingState>>,
|
||||
{
|
||||
let Router {
|
||||
state,
|
||||
routes,
|
||||
node,
|
||||
fallback,
|
||||
_marker: _,
|
||||
} = other.into();
|
||||
|
||||
debug_assert!(state.is_none());
|
||||
|
||||
for (id, route) in routes {
|
||||
let path = node
|
||||
.route_id_to_path
|
||||
@@ -289,7 +352,7 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
L: Layer<Route<B>>,
|
||||
L::Service:
|
||||
@@ -322,9 +385,11 @@ where
|
||||
let fallback = self.fallback.map(|svc| Route::new(layer.layer(svc)));
|
||||
|
||||
Router {
|
||||
state: self.state,
|
||||
routes,
|
||||
node: self.node,
|
||||
fallback,
|
||||
_marker: self._marker,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,9 +424,11 @@ where
|
||||
.collect();
|
||||
|
||||
Router {
|
||||
state: self.state,
|
||||
routes,
|
||||
node: self.node,
|
||||
fallback: self.fallback,
|
||||
_marker: self._marker,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +473,13 @@ where
|
||||
pub fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C> {
|
||||
IntoMakeServiceWithConnectInfo::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B> Router<S, B, WithState>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
#[inline]
|
||||
fn call_route(
|
||||
&self,
|
||||
@@ -442,6 +515,10 @@ where
|
||||
|
||||
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
|
||||
.routes
|
||||
.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
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
type Response = Response;
|
||||
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.
|
||||
#[derive(Clone, Default)]
|
||||
struct Node {
|
||||
@@ -599,5 +683,6 @@ impl<B> fmt::Debug for Endpoint<B> {
|
||||
#[allow(warnings)]
|
||||
fn traits() {
|
||||
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() {
|
||||
let app = Router::new()
|
||||
.route("/foo", get(|| async {}))
|
||||
.fallback((|| async { "fallback" }).into_service());
|
||||
.fallback((|| async { "fallback" }).into_service())
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -20,7 +21,8 @@ async fn basic() {
|
||||
async fn nest() {
|
||||
let app = Router::new()
|
||||
.nest("/foo", Router::new().route("/bar", get(|| async {})))
|
||||
.fallback((|| async { "fallback" }).into_service());
|
||||
.fallback((|| async { "fallback" }).into_service())
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -38,7 +40,8 @@ async fn or() {
|
||||
|
||||
let app = one
|
||||
.merge(two)
|
||||
.fallback((|| async { "fallback" }).into_service());
|
||||
.fallback((|| async { "fallback" }).into_service())
|
||||
.state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
@@ -8,14 +8,16 @@ mod for_handlers {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_handles_head() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
get(|| async {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("x-some-header", "foobar".parse().unwrap());
|
||||
(headers, "you shouldn't see this")
|
||||
}),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
get(|| async {
|
||||
let mut headers = HeaderMap::new();
|
||||
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
|
||||
let res = app
|
||||
@@ -43,14 +45,16 @@ mod for_services {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_handles_head() {
|
||||
let app = Router::new().route(
|
||||
"/",
|
||||
get_service(service_fn(|_req: Request<Body>| async move {
|
||||
Ok::<_, Infallible>(
|
||||
([("x-some-header", "foobar")], "you shouldn't see this").into_response(),
|
||||
)
|
||||
})),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
get_service(service_fn(|_req: Request<Body>| async move {
|
||||
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
|
||||
let res = app
|
||||
|
||||
@@ -31,7 +31,7 @@ impl<R> Service<R> for Svc {
|
||||
|
||||
#[tokio::test]
|
||||
async fn handler() {
|
||||
let app = Router::new().route(
|
||||
let app = Router::with_state(()).route(
|
||||
"/",
|
||||
get(forever.layer(
|
||||
ServiceBuilder::new()
|
||||
@@ -50,7 +50,7 @@ async fn handler() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn handler_multiple_methods_first() {
|
||||
let app = Router::new().route(
|
||||
let app = Router::with_state(()).route(
|
||||
"/",
|
||||
get(forever.layer(
|
||||
ServiceBuilder::new()
|
||||
@@ -70,7 +70,7 @@ async fn handler_multiple_methods_first() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn handler_multiple_methods_middle() {
|
||||
let app = Router::new().route(
|
||||
let app = Router::with_state(()).route(
|
||||
"/",
|
||||
delete(unit)
|
||||
.get(
|
||||
@@ -93,7 +93,7 @@ async fn handler_multiple_methods_middle() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn handler_multiple_methods_last() {
|
||||
let app = Router::new().route(
|
||||
let app = Router::with_state(()).route(
|
||||
"/",
|
||||
delete(unit).get(
|
||||
forever.layer(
|
||||
|
||||
@@ -12,7 +12,7 @@ async fn basic() {
|
||||
.route("/foo", get(|| async {}))
|
||||
.route("/bar", 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);
|
||||
|
||||
@@ -41,7 +41,8 @@ async fn multiple_ors_balanced_differently() {
|
||||
one.clone()
|
||||
.merge(two.clone())
|
||||
.merge(three.clone())
|
||||
.merge(four.clone()),
|
||||
.merge(four.clone())
|
||||
.state(()),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -49,18 +50,20 @@ async fn multiple_ors_balanced_differently() {
|
||||
"two",
|
||||
one.clone()
|
||||
.merge(two.clone())
|
||||
.merge(three.clone().merge(four.clone())),
|
||||
.merge(three.clone().merge(four.clone()))
|
||||
.state(()),
|
||||
)
|
||||
.await;
|
||||
|
||||
test(
|
||||
"three",
|
||||
one.clone()
|
||||
.merge(two.clone().merge(three.clone()).merge(four.clone())),
|
||||
.merge(two.clone().merge(three.clone()).merge(four.clone()))
|
||||
.state(()),
|
||||
)
|
||||
.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)
|
||||
where
|
||||
@@ -89,11 +92,11 @@ async fn nested_or() {
|
||||
|
||||
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("/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/baz").send().await.text().await, "baz");
|
||||
}
|
||||
@@ -102,7 +105,10 @@ async fn nested_or() {
|
||||
async fn or_with_route_following() {
|
||||
let one = Router::new().route("/one", get(|| async { "one" }));
|
||||
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);
|
||||
|
||||
@@ -122,7 +128,7 @@ async fn layer() {
|
||||
let two = Router::new()
|
||||
.route("/bar", get(|| async {}))
|
||||
.layer(ConcurrencyLimitLayer::new(10));
|
||||
let app = one.merge(two);
|
||||
let app = one.merge(two).state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
@@ -145,7 +151,7 @@ async fn layer_and_handle_error() {
|
||||
}))
|
||||
.layer(TimeoutLayer::new(Duration::from_millis(10))),
|
||||
);
|
||||
let app = one.merge(two);
|
||||
let app = one.merge(two).state(());
|
||||
|
||||
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 app = one.merge(two);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/bar/baz").send().await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -171,7 +177,7 @@ async fn boxed() {
|
||||
let two = Router::new().route("/bar", get(|| async {}));
|
||||
let app = one.merge(two);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/bar").send().await;
|
||||
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("/r7", get(|| async {})));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
for n in 1..=7 {
|
||||
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;
|
||||
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 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;
|
||||
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 client = TestClient::new(one.merge(two));
|
||||
let client = TestClient::new(one.merge(two).state(()));
|
||||
|
||||
let res = client.get("/foo/bar/baz").send().await;
|
||||
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 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;
|
||||
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 client = TestClient::new(one.merge(two));
|
||||
let client = TestClient::new(one.merge(two).state(()));
|
||||
|
||||
let res = client.get("/one/foo/bar").send().await;
|
||||
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 client = TestClient::new(private.merge(public));
|
||||
let client = TestClient::new(private.merge(public).state(()));
|
||||
|
||||
assert_eq!(
|
||||
client.get("/").send().await.status(),
|
||||
|
||||
@@ -46,7 +46,7 @@ async fn hello_world() {
|
||||
.route("/", get(root).post(foo))
|
||||
.route("/users", post(users_create));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
let body = res.text().await;
|
||||
@@ -75,7 +75,7 @@ async fn routing() {
|
||||
get(|_: Request<Body>| async { "users#action" }),
|
||||
);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
@@ -99,7 +99,7 @@ async fn routing() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn router_type_doesnt_change() {
|
||||
let app: Router = Router::new()
|
||||
let app: Router<()> = Router::new()
|
||||
.route(
|
||||
"/",
|
||||
on(MethodFilter::GET, |_: Request<Body>| async {
|
||||
@@ -111,7 +111,7 @@ async fn router_type_doesnt_change() {
|
||||
)
|
||||
.layer(tower_http::compression::CompressionLayer::new());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -149,7 +149,7 @@ async fn routing_between_services() {
|
||||
)
|
||||
.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;
|
||||
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 body = res.text().await;
|
||||
@@ -203,7 +203,7 @@ async fn service_in_bottom() {
|
||||
|
||||
let app = Router::new().route("/", get_service(service_fn(handler)));
|
||||
|
||||
TestClient::new(app);
|
||||
TestClient::new(app.state(()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -212,7 +212,7 @@ async fn wrong_method_handler() {
|
||||
.route("/", get(|| async {}).post(|| async {}))
|
||||
.route("/foo", patch(|| async {}));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.patch("/").send().await;
|
||||
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("/foo", patch_service(Svc));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.patch("/").send().await;
|
||||
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 client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -286,7 +286,7 @@ async fn multiple_methods_for_one_handler() {
|
||||
async fn wildcard_sees_whole_url() {
|
||||
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;
|
||||
assert_eq!(res.text().await, "/api/foo/bar");
|
||||
@@ -305,7 +305,7 @@ async fn middleware_applies_to_routes_above() {
|
||||
)
|
||||
.route("/two", get(|| async {}));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/one").send().await;
|
||||
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() {
|
||||
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;
|
||||
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() {
|
||||
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;
|
||||
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 { "with tsr" }));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/foo/").send().await;
|
||||
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 }),
|
||||
);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/x").send().await;
|
||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
@@ -384,7 +384,7 @@ async fn static_and_dynamic_paths() {
|
||||
)
|
||||
.route("/foo", get(|| async { "static" }));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/bar").send().await;
|
||||
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")]
|
||||
async fn empty_route() {
|
||||
let app = Router::new().route("", get(|| async {}));
|
||||
TestClient::new(app);
|
||||
TestClient::new(app.state(()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -429,7 +429,7 @@ async fn middleware_still_run_for_unmatched_requests() {
|
||||
.route("/", get(|| async {}))
|
||||
.layer(tower::layer::layer_fn(CountMiddleware));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
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"
|
||||
)]
|
||||
async fn routing_to_router_panics() {
|
||||
TestClient::new(Router::new().route("/", Router::new()));
|
||||
TestClient::new(Router::new().route("/", Router::new().state(())).state(()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -454,7 +454,7 @@ async fn route_layer() {
|
||||
.route("/foo", get(|| async {}))
|
||||
.route_layer(RequireAuthorizationLayer::bearer("password"));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client
|
||||
.get("/foo")
|
||||
@@ -482,7 +482,7 @@ async fn different_methods_added_in_different_routes() {
|
||||
.route("/", get(|| async { "GET" }))
|
||||
.route("/", post(|| async { "POST" }));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().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 body = res.text().await;
|
||||
@@ -522,7 +522,7 @@ async fn merging_routers_with_fallbacks_panics() {
|
||||
async fn fallback() {}
|
||||
let one = 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]
|
||||
@@ -531,7 +531,7 @@ async fn nesting_router_with_fallbacks_panics() {
|
||||
async fn fallback() {}
|
||||
let one = Router::new().fallback(fallback.into_service());
|
||||
let app = Router::new().nest("/", one);
|
||||
TestClient::new(app);
|
||||
TestClient::new(app.state(()));
|
||||
}
|
||||
|
||||
#[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 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 body = res.text().await;
|
||||
@@ -556,7 +556,7 @@ async fn head_content_length_through_hyper_server() {
|
||||
.route("/", get(|| async { "foo" }))
|
||||
.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;
|
||||
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() {
|
||||
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;
|
||||
assert_eq!(res.headers()["content-length"], "3");
|
||||
@@ -585,7 +585,7 @@ async fn head_with_middleware_applied() {
|
||||
.route("/", get(|| async { "Hello, World!" }))
|
||||
.layer(CompressionLayer::new().compress_when(SizeAbove::new(0)));
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
// send GET request
|
||||
let res = client
|
||||
@@ -614,7 +614,7 @@ async fn head_with_middleware_applied() {
|
||||
#[should_panic(expected = "Paths must start with a `/`")]
|
||||
async fn routes_must_start_with_slash() {
|
||||
let app = Router::new().route(":foo", get(|| async {}));
|
||||
TestClient::new(app);
|
||||
TestClient::new(app.state(()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -630,7 +630,7 @@ async fn limited_body_with_content_length() {
|
||||
)
|
||||
.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;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -652,7 +652,7 @@ async fn limited_body_with_streaming_body() {
|
||||
)
|
||||
.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 res = client
|
||||
|
||||
@@ -40,7 +40,7 @@ async fn nesting_apps() {
|
||||
.route("/", get(|| async { "hi" }))
|
||||
.nest("/:version/api", api_routes);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -64,7 +64,7 @@ async fn wrong_method_nest() {
|
||||
let nested_app = Router::new().route("/", get(|| async {}));
|
||||
let app = Router::new().nest("/", nested_app);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
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 app = Router::new().nest("/", nested);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
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 app = Router::new().nest("", nested);
|
||||
|
||||
let client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
|
||||
let res = client.get("/").send().await;
|
||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
@@ -116,7 +116,7 @@ async fn nesting_router_at_empty_path() {
|
||||
async fn nesting_handler_at_root() {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -229,7 +229,7 @@ async fn nested_multiple_routes() {
|
||||
)
|
||||
.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("/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" })),
|
||||
);
|
||||
|
||||
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/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" }));
|
||||
|
||||
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/users").send().await.text().await, "users");
|
||||
@@ -282,7 +282,7 @@ async fn multiple_top_level_nests() {
|
||||
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("/two/route").send().await.text().await, "two");
|
||||
@@ -291,7 +291,7 @@ async fn multiple_top_level_nests() {
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "Invalid route: nested routes 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]
|
||||
@@ -333,7 +333,7 @@ async fn outer_middleware_still_see_whole_url() {
|
||||
.fallback(handler.into_service())
|
||||
.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("/foo").send().await.text().await, "/foo");
|
||||
@@ -352,11 +352,12 @@ async fn nest_at_capture() {
|
||||
"/:b",
|
||||
get(|Path((a, b)): Path<(String, String)>| async move { format!("a={} b={}", a, b) }),
|
||||
)
|
||||
.state(())
|
||||
.boxed_clone();
|
||||
|
||||
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;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -367,7 +368,7 @@ async fn nest_at_capture() {
|
||||
async fn nest_with_and_without_trailing() {
|
||||
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;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
@@ -393,14 +394,14 @@ macro_rules! nested_route_test {
|
||||
async fn $name() {
|
||||
let inner = Router::new().route($route_path, get(|| async {}));
|
||||
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 status = res.status();
|
||||
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 client = TestClient::new(app);
|
||||
let client = TestClient::new(app.state(()));
|
||||
let res = client.get(dbg!($expected_path)).send().await;
|
||||
assert_eq!(res.status(), StatusCode::OK, "opaque");
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ mod tests {
|
||||
user_agent.to_string()
|
||||
}
|
||||
|
||||
let app = Router::new().route("/", get(handle));
|
||||
let app = Router::new().route("/", get(handle)).state(());
|
||||
|
||||
let client = TestClient::new(app);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user