mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-02 00:00:22 +02:00
add state parameter to router
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user