diff --git a/CHANGELOG.md b/CHANGELOG.md index 171fc4be..25d84376 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Overall compile time improvements. If you're having issues with compile time please file an issue! -- Remove `prelude`. Explicit imports are now required. -- Add dedicated `Router` to replace the `RoutingDsl` trait +- Remove `prelude`. Explicit imports are now required ([#195](https://github.com/tokio-rs/axum/pull/195)) +- Add dedicated `Router` to replace the `RoutingDsl` trait ([#214](https://github.com/tokio-rs/axum/pull/214)) +- Replace `axum::route(...)` with `axum::Router::new().route(...)`. This means + there is now only one way to create a new router. Same goes for + `axum::routing::nest`. ([#215](https://github.com/tokio-rs/axum/pull/215)) - Make `FromRequest` default to being generic over `body::Body` ([#146](https://github.com/tokio-rs/axum/pull/146)) - Implement `std::error::Error` for all rejections ([#153](https://github.com/tokio-rs/axum/pull/153)) - Add `Router::or` for combining routes ([#108](https://github.com/tokio-rs/axum/pull/108)) diff --git a/examples/async-graphql/src/main.rs b/examples/async-graphql/src/main.rs index 3d649d6d..e06b9438 100644 --- a/examples/async-graphql/src/main.rs +++ b/examples/async-graphql/src/main.rs @@ -3,7 +3,7 @@ mod starwars; use async_graphql::http::{playground_source, GraphQLPlaygroundConfig}; use async_graphql::{EmptyMutation, EmptySubscription, Request, Response, Schema}; use axum::response::IntoResponse; -use axum::{extract::Extension, handler::get, response::Html, route, AddExtensionLayer, Json}; +use axum::{extract::Extension, handler::get, response::Html, AddExtensionLayer, Json, Router}; use starwars::{QueryRoot, StarWars, StarWarsSchema}; async fn graphql_handler(schema: Extension, req: Json) -> Json { @@ -20,7 +20,8 @@ async fn main() { .data(StarWars::new()) .finish(); - let app = route("/", get(graphql_playground).post(graphql_handler)) + let app = Router::new() + .route("/", get(graphql_playground).post(graphql_handler)) .layer(AddExtensionLayer::new(schema)); println!("Playground: http://localhost:3000"); diff --git a/examples/chat/src/main.rs b/examples/chat/src/main.rs index 1bfeddd1..a44ae298 100644 --- a/examples/chat/src/main.rs +++ b/examples/chat/src/main.rs @@ -10,8 +10,8 @@ use axum::extract::ws::{Message, WebSocket, WebSocketUpgrade}; use axum::extract::Extension; use axum::handler::get; use axum::response::{Html, IntoResponse}; -use axum::route; use axum::AddExtensionLayer; +use axum::Router; use futures::{sink::SinkExt, stream::StreamExt}; use std::collections::HashSet; use std::net::SocketAddr; @@ -31,7 +31,8 @@ async fn main() { let app_state = Arc::new(AppState { user_set, tx }); - let app = route("/", get(index)) + let app = Router::new() + .route("/", get(index)) .route("/websocket", get(websocket_handler)) .layer(AddExtensionLayer::new(app_state)); diff --git a/examples/error-handling-and-dependency-injection/src/main.rs b/examples/error-handling-and-dependency-injection/src/main.rs index 87033773..7ffa75d8 100644 --- a/examples/error-handling-and-dependency-injection/src/main.rs +++ b/examples/error-handling-and-dependency-injection/src/main.rs @@ -14,7 +14,7 @@ use axum::{ handler::{get, post}, http::{Response, StatusCode}, response::IntoResponse, - route, AddExtensionLayer, Json, + AddExtensionLayer, Json, Router, }; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -37,7 +37,8 @@ async fn main() { let user_repo = Arc::new(ExampleUserRepo) as DynUserRepo; // Build our application with some routes - let app = route("/users/:id", get(users_show)) + let app = Router::new() + .route("/users/:id", get(users_show)) .route("/users", post(users_create)) // Add our `user_repo` to all request's extensions so handlers can access // it. diff --git a/examples/form/src/main.rs b/examples/form/src/main.rs index e74b88fe..68dbde1a 100644 --- a/examples/form/src/main.rs +++ b/examples/form/src/main.rs @@ -4,7 +4,7 @@ //! cargo run -p example-form //! ``` -use axum::{extract::Form, handler::get, response::Html, route}; +use axum::{extract::Form, handler::get, response::Html, Router}; use serde::Deserialize; use std::net::SocketAddr; @@ -17,7 +17,7 @@ async fn main() { tracing_subscriber::fmt::init(); // build our application with some routes - let app = route("/", get(show_form).post(accept_form)); + let app = Router::new().route("/", get(show_form).post(accept_form)); // run it with hyper let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); diff --git a/examples/global-404-handler/src/main.rs b/examples/global-404-handler/src/main.rs index 30c08caf..16783b2f 100644 --- a/examples/global-404-handler/src/main.rs +++ b/examples/global-404-handler/src/main.rs @@ -9,7 +9,7 @@ use axum::{ handler::get, http::{Response, StatusCode}, response::Html, - route, + Router, }; use std::net::SocketAddr; use tower::util::MapResponseLayer; @@ -23,7 +23,8 @@ async fn main() { tracing_subscriber::fmt::init(); // build our application with a route - let app = route("/", get(handler)) + let app = Router::new() + .route("/", get(handler)) // make sure this is added as the very last thing .layer(MapResponseLayer::new(map_404)); diff --git a/examples/hello-world/src/main.rs b/examples/hello-world/src/main.rs index 03b14363..f5532084 100644 --- a/examples/hello-world/src/main.rs +++ b/examples/hello-world/src/main.rs @@ -4,13 +4,13 @@ //! cargo run -p example-hello-world //! ``` -use axum::{handler::get, route}; +use axum::{handler::get, Router}; use std::net::SocketAddr; #[tokio::main] async fn main() { // build our application with a route - let app = route("/foo", get(handler)); + let app = Router::new().route("/", get(handler)); // run it let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); diff --git a/examples/key-value-store/src/main.rs b/examples/key-value-store/src/main.rs index f16c1a23..464fe9f5 100644 --- a/examples/key-value-store/src/main.rs +++ b/examples/key-value-store/src/main.rs @@ -12,8 +12,8 @@ use axum::{ handler::{delete, get, Handler}, http::StatusCode, response::IntoResponse, - route, - routing::{BoxRoute, Router}, + routing::BoxRoute, + Router, }; use std::{ borrow::Cow, @@ -38,29 +38,30 @@ async fn main() { tracing_subscriber::fmt::init(); // Build our application by composing routes - let app = route( - "/:key", - // Add compression to `kv_get` - get(kv_get.layer(CompressionLayer::new())) - // But don't compress `kv_set` - .post(kv_set), - ) - .route("/keys", get(list_keys)) - // Nest our admin routes under `/admin` - .nest("/admin", admin_routes()) - // Add middleware to all routes - .layer( - ServiceBuilder::new() - .load_shed() - .concurrency_limit(1024) - .timeout(Duration::from_secs(10)) - .layer(TraceLayer::new_for_http()) - .layer(AddExtensionLayer::new(SharedState::default())) - .into_inner(), - ) - // Handle errors from middleware - .handle_error(handle_error) - .check_infallible(); + let app = Router::new() + .route( + "/:key", + // Add compression to `kv_get` + get(kv_get.layer(CompressionLayer::new())) + // But don't compress `kv_set` + .post(kv_set), + ) + .route("/keys", get(list_keys)) + // Nest our admin routes under `/admin` + .nest("/admin", admin_routes()) + // Add middleware to all routes + .layer( + ServiceBuilder::new() + .load_shed() + .concurrency_limit(1024) + .timeout(Duration::from_secs(10)) + .layer(TraceLayer::new_for_http()) + .layer(AddExtensionLayer::new(SharedState::default())) + .into_inner(), + ) + // Handle errors from middleware + .handle_error(handle_error) + .check_infallible(); // Run our app with hyper let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); @@ -117,7 +118,8 @@ fn admin_routes() -> Router { state.write().unwrap().db.remove(&key); } - route("/keys", delete(delete_all_keys)) + Router::new() + .route("/keys", delete(delete_all_keys)) .route("/key/:key", delete(remove_key)) // Require bearer auth for all admin routes .layer(RequireAuthorizationLayer::bearer("secret-token")) diff --git a/examples/multipart-form/src/main.rs b/examples/multipart-form/src/main.rs index cd6017ef..3371eb48 100644 --- a/examples/multipart-form/src/main.rs +++ b/examples/multipart-form/src/main.rs @@ -8,7 +8,7 @@ use axum::{ extract::{ContentLengthLimit, Multipart}, handler::get, response::Html, - route, + Router, }; use std::net::SocketAddr; @@ -21,7 +21,8 @@ async fn main() { tracing_subscriber::fmt::init(); // build our application with some routes - let app = route("/", get(show_form).post(accept_form)) + let app = Router::new() + .route("/", get(show_form).post(accept_form)) .layer(tower_http::trace::TraceLayer::new_for_http()); // run it with hyper diff --git a/examples/oauth/src/main.rs b/examples/oauth/src/main.rs index 5c392bee..36a7bb08 100644 --- a/examples/oauth/src/main.rs +++ b/examples/oauth/src/main.rs @@ -14,7 +14,7 @@ use axum::{ handler::get, http::{header::SET_COOKIE, HeaderMap, Response}, response::{IntoResponse, Redirect}, - route, AddExtensionLayer, + AddExtensionLayer, Router, }; use oauth2::{ basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId, @@ -42,8 +42,11 @@ async fn main() { // `MemoryStore` just used as an example. Don't use this in production. let store = MemoryStore::new(); + let oauth_client = oauth_client(); - let app = route("/", get(index)) + + let app = Router::new() + .route("/", get(index)) .route("/auth/discord", get(discord_auth)) .route("/auth/authorized", get(login_authorized)) .route("/protected", get(protected)) diff --git a/examples/sessions/src/main.rs b/examples/sessions/src/main.rs index afde44e3..d40c995f 100644 --- a/examples/sessions/src/main.rs +++ b/examples/sessions/src/main.rs @@ -15,7 +15,7 @@ use axum::{ StatusCode, }, response::IntoResponse, - route, AddExtensionLayer, + AddExtensionLayer, Router, }; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; @@ -32,7 +32,9 @@ async fn main() { // `MemoryStore` just used as an example. Don't use this in production. let store = MemoryStore::new(); - let app = route("/", get(handler)).layer(AddExtensionLayer::new(store)); + let app = Router::new() + .route("/", get(handler)) + .layer(AddExtensionLayer::new(store)); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); tracing::debug!("listening on {}", addr); diff --git a/examples/sse/src/main.rs b/examples/sse/src/main.rs index 26c87a3e..aa2fc7c4 100644 --- a/examples/sse/src/main.rs +++ b/examples/sse/src/main.rs @@ -9,7 +9,7 @@ use axum::{ handler::get, http::StatusCode, response::sse::{sse, Event, Sse}, - routing::nest, + Router, }; use futures::stream::{self, Stream}; use std::{convert::Infallible, net::SocketAddr, time::Duration}; @@ -35,7 +35,8 @@ async fn main() { }); // build our application with a route - let app = nest("/", static_files_service) + let app = Router::new() + .nest("/", static_files_service) .route("/sse", get(sse_handler)) .layer(TraceLayer::new_for_http()); diff --git a/examples/static-file-server/src/main.rs b/examples/static-file-server/src/main.rs index a8d4775d..165fc82a 100644 --- a/examples/static-file-server/src/main.rs +++ b/examples/static-file-server/src/main.rs @@ -4,8 +4,8 @@ //! cargo run -p example-static-file-server //! ``` -use axum::{http::StatusCode, routing::nest}; -use std::net::SocketAddr; +use axum::{http::StatusCode, service, Router}; +use std::{convert::Infallible, net::SocketAddr}; use tower_http::{services::ServeDir, trace::TraceLayer}; #[tokio::main] @@ -19,16 +19,17 @@ async fn main() { } tracing_subscriber::fmt::init(); - let app = nest( - "/static", - axum::service::get(ServeDir::new(".")).handle_error(|error: std::io::Error| { - Ok::<_, std::convert::Infallible>(( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Unhandled internal error: {}", error), - )) - }), - ) - .layer(TraceLayer::new_for_http()); + let app = Router::new() + .nest( + "/static", + service::get(ServeDir::new(".")).handle_error(|error: std::io::Error| { + Ok::<_, Infallible>(( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + )) + }), + ) + .layer(TraceLayer::new_for_http()); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); tracing::debug!("listening on {}", addr); diff --git a/examples/templates/src/main.rs b/examples/templates/src/main.rs index 70e1076d..f8abf340 100644 --- a/examples/templates/src/main.rs +++ b/examples/templates/src/main.rs @@ -11,7 +11,7 @@ use axum::{ handler::get, http::{Response, StatusCode}, response::{Html, IntoResponse}, - route, + Router, }; use std::{convert::Infallible, net::SocketAddr}; @@ -24,7 +24,7 @@ async fn main() { tracing_subscriber::fmt::init(); // build our application with some routes - let app = route("/greet/:name", get(greet)); + let app = Router::new().route("/greet/:name", get(greet)); // run it let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); diff --git a/examples/testing/src/main.rs b/examples/testing/src/main.rs index a7c15f6d..0fc40695 100644 --- a/examples/testing/src/main.rs +++ b/examples/testing/src/main.rs @@ -6,9 +6,8 @@ use axum::{ handler::{get, post}, - route, - routing::{BoxRoute, Router}, - Json, + routing::BoxRoute, + Json, Router, }; use tower_http::trace::TraceLayer; @@ -34,7 +33,8 @@ async fn main() { /// without having to create an HTTP server. #[allow(dead_code)] fn app() -> Router { - route("/", get(|| async { "Hello, World!" })) + Router::new() + .route("/", get(|| async { "Hello, World!" })) .route( "/json", post(|payload: Json| async move { diff --git a/examples/tls-rustls/src/main.rs b/examples/tls-rustls/src/main.rs index b7a4b035..bb051269 100644 --- a/examples/tls-rustls/src/main.rs +++ b/examples/tls-rustls/src/main.rs @@ -4,7 +4,7 @@ //! cargo run -p example-tls-rustls //! ``` -use axum::{handler::get, route}; +use axum::{handler::get, Router}; use hyper::server::conn::Http; use std::{fs::File, io::BufReader, sync::Arc}; use tokio::net::TcpListener; @@ -31,7 +31,7 @@ async fn main() { let acceptor = TlsAcceptor::from(rustls_config); let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap(); - let app = route("/", get(handler)); + let app = Router::new().route("/", get(handler)); loop { let (stream, _addr) = listener.accept().await.unwrap(); diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index e5b02e20..b8dc6fa1 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -18,7 +18,7 @@ use axum::{ handler::{get, patch}, http::StatusCode, response::IntoResponse, - route, Json, + Json, Router, }; use serde::{Deserialize, Serialize}; use std::{ @@ -43,7 +43,8 @@ async fn main() { let db = Db::default(); // Compose the routes - let app = route("/todos", get(todos_index).post(todos_create)) + let app = Router::new() + .route("/todos", get(todos_index).post(todos_create)) .route("/todos/:id", patch(todos_update).delete(todos_delete)) // Add middleware to all routes .layer( @@ -53,7 +54,6 @@ async fn main() { .layer(AddExtensionLayer::new(db)) .into_inner(), ) - // If the timeout fails, map the error to a response .handle_error(|error: BoxError| { let result = if error.is::() { Ok(StatusCode::REQUEST_TIMEOUT) diff --git a/examples/tokio-postgres/src/main.rs b/examples/tokio-postgres/src/main.rs index 3123b754..4321e82f 100644 --- a/examples/tokio-postgres/src/main.rs +++ b/examples/tokio-postgres/src/main.rs @@ -9,7 +9,7 @@ use axum::{ extract::{Extension, FromRequest, RequestParts}, handler::get, http::StatusCode, - route, AddExtensionLayer, + AddExtensionLayer, Router, }; use bb8::{Pool, PooledConnection}; use bb8_postgres::PostgresConnectionManager; @@ -31,11 +31,12 @@ async fn main() { let pool = Pool::builder().build(manager).await.unwrap(); // build our application with some routes - let app = route( - "/", - get(using_connection_pool_extractor).post(using_connection_extractor), - ) - .layer(AddExtensionLayer::new(pool)); + let app = Router::new() + .route( + "/", + get(using_connection_pool_extractor).post(using_connection_extractor), + ) + .layer(AddExtensionLayer::new(pool)); // run it with hyper let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); diff --git a/examples/tracing-aka-logging/src/main.rs b/examples/tracing-aka-logging/src/main.rs index 03a39f9c..52a19673 100644 --- a/examples/tracing-aka-logging/src/main.rs +++ b/examples/tracing-aka-logging/src/main.rs @@ -4,7 +4,7 @@ //! cargo run -p example-tracing-aka-logging //! ``` -use axum::{handler::get, response::Html, route}; +use axum::{handler::get, response::Html, Router}; use std::net::SocketAddr; use tower_http::trace::TraceLayer; @@ -20,7 +20,8 @@ async fn main() { tracing_subscriber::fmt::init(); // build our application with a route - let app = route("/", get(handler)) + let app = Router::new() + .route("/", get(handler)) // `TraceLayer` is provided by tower-http so you have to add that as a dependency. // It provides good defaults but is also very customizable. // See https://docs.rs/tower-http/0.1.1/tower_http/trace/index.html for more details. diff --git a/examples/unix-domain-socket/src/main.rs b/examples/unix-domain-socket/src/main.rs index 5d23c39c..28579160 100644 --- a/examples/unix-domain-socket/src/main.rs +++ b/examples/unix-domain-socket/src/main.rs @@ -9,7 +9,7 @@ use axum::{ extract::connect_info::{self, ConnectInfo}, handler::get, http::{Method, Request, StatusCode, Uri}, - route, + Router, }; use futures::ready; use hyper::{ @@ -53,7 +53,7 @@ async fn main() { let uds = UnixListener::bind(path.clone()).unwrap(); tokio::spawn(async { - let app = route("/", get(handler)); + let app = Router::new().route("/", get(handler)); axum::Server::builder(ServerAccept { uds }) .serve(app.into_make_service_with_connect_info::()) diff --git a/examples/versioning/src/main.rs b/examples/versioning/src/main.rs index a5bca134..1943d0ec 100644 --- a/examples/versioning/src/main.rs +++ b/examples/versioning/src/main.rs @@ -11,7 +11,7 @@ use axum::{ handler::get, http::{Response, StatusCode}, response::IntoResponse, - route, + Router, }; use std::collections::HashMap; use std::net::SocketAddr; @@ -25,7 +25,7 @@ async fn main() { tracing_subscriber::fmt::init(); // build our application with some routes - let app = route("/:version/foo", get(handler)); + let app = Router::new().route("/:version/foo", get(handler)); // run it let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); diff --git a/examples/websockets/src/main.rs b/examples/websockets/src/main.rs index 71403aa1..44f49016 100644 --- a/examples/websockets/src/main.rs +++ b/examples/websockets/src/main.rs @@ -14,7 +14,7 @@ use axum::{ handler::get, http::StatusCode, response::IntoResponse, - routing::nest, + Router, }; use std::net::SocketAddr; use tower_http::{ @@ -31,25 +31,27 @@ async fn main() { tracing_subscriber::fmt::init(); // build our application with some routes - let app = nest( - "/", - axum::service::get( - ServeDir::new("examples/websockets/assets").append_index_html_on_directories(true), + let app = Router::new() + .nest( + "/", + axum::service::get( + ServeDir::new("examples/websockets/assets").append_index_html_on_directories(true), + ) + .handle_error(|error: std::io::Error| { + Ok::<_, std::convert::Infallible>(( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled internal error: {}", error), + )) + }), ) - .handle_error(|error: std::io::Error| { - Ok::<_, std::convert::Infallible>(( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Unhandled internal error: {}", error), - )) - }), - ) - // routes are matched from bottom to top, so we have to put `nest` at the - // top since it matches all routes - .route("/ws", get(ws_handler)) - // logging so we can see whats going on - .layer( - TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::default().include_headers(true)), - ); + // routes are matched from bottom to top, so we have to put `nest` at the + // top since it matches all routes + .route("/ws", get(ws_handler)) + // logging so we can see whats going on + .layer( + TraceLayer::new_for_http() + .make_span_with(DefaultMakeSpan::default().include_headers(true)), + ); // run it with hyper let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); diff --git a/src/extract/connect_info.rs b/src/extract/connect_info.rs index dd510ad0..6fd23c0f 100644 --- a/src/extract/connect_info.rs +++ b/src/extract/connect_info.rs @@ -131,7 +131,7 @@ where mod tests { use super::*; use crate::Server; - use crate::{handler::get, route}; + use crate::{handler::get, Router}; use std::net::{SocketAddr, TcpListener}; #[tokio::test] @@ -145,7 +145,7 @@ mod tests { let (tx, rx) = tokio::sync::oneshot::channel(); tokio::spawn(async move { - let app = route("/", get(handler)); + let app = Router::new().route("/", get(handler)); let server = Server::from_tcp(listener) .unwrap() .serve(app.into_make_service_with_connect_info::()); @@ -187,7 +187,7 @@ mod tests { let (tx, rx) = tokio::sync::oneshot::channel(); tokio::spawn(async move { - let app = route("/", get(handler)); + let app = Router::new().route("/", get(handler)); let server = Server::from_tcp(listener) .unwrap() .serve(app.into_make_service_with_connect_info::()); diff --git a/src/extract/content_length_limit.rs b/src/extract/content_length_limit.rs index 08dd83d8..3313ac03 100644 --- a/src/extract/content_length_limit.rs +++ b/src/extract/content_length_limit.rs @@ -12,14 +12,14 @@ use std::ops::Deref; /// use axum::{ /// extract::ContentLengthLimit, /// handler::post, -/// route, +/// Router, /// }; /// /// async fn handler(body: ContentLengthLimit) { /// // ... /// } /// -/// let app = route("/", post(handler)); +/// let app = Router::new().route("/", post(handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/extract/extension.rs b/src/extract/extension.rs index ed73c42f..7e6765d5 100644 --- a/src/extract/extension.rs +++ b/src/extract/extension.rs @@ -13,7 +13,7 @@ use std::ops::Deref; /// AddExtensionLayer, /// extract::Extension, /// handler::get, -/// route, +/// Router, /// }; /// use std::sync::Arc; /// @@ -28,7 +28,7 @@ use std::ops::Deref; /// /// let state = Arc::new(State { /* ... */ }); /// -/// let app = route("/", get(handler)) +/// let app = Router::new().route("/", get(handler)) /// // Add middleware that inserts the state into all incoming request's /// // extensions. /// .layer(AddExtensionLayer::new(state)); diff --git a/src/extract/extractor_middleware.rs b/src/extract/extractor_middleware.rs index 863e5e48..79351f84 100644 --- a/src/extract/extractor_middleware.rs +++ b/src/extract/extractor_middleware.rs @@ -37,7 +37,7 @@ use tower::{BoxError, Layer, Service}; /// use axum::{ /// extract::{extractor_middleware, FromRequest, RequestParts}, /// handler::{get, post}, -/// route, +/// Router, /// }; /// use http::StatusCode; /// use async_trait::async_trait; @@ -76,7 +76,8 @@ use tower::{BoxError, Layer, Service}; /// // If we get here the request has been authorized /// } /// -/// let app = route("/", get(handler)) +/// let app = Router::new() +/// .route("/", get(handler)) /// .route("/foo", post(other_handler)) /// // The extractor will run before all routes /// .layer(extractor_middleware::()); diff --git a/src/extract/form.rs b/src/extract/form.rs index bfdb578f..1aa03240 100644 --- a/src/extract/form.rs +++ b/src/extract/form.rs @@ -17,7 +17,7 @@ use tower::BoxError; /// use axum::{ /// extract::Form, /// handler::post, -/// route, +/// Router, /// }; /// use serde::Deserialize; /// @@ -33,7 +33,7 @@ use tower::BoxError; /// // ... /// } /// -/// let app = route("/sign_up", post(accept_form)); +/// let app = Router::new().route("/sign_up", post(accept_form)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/extract/mod.rs b/src/extract/mod.rs index 027b0ce7..b9946eac 100644 --- a/src/extract/mod.rs +++ b/src/extract/mod.rs @@ -11,7 +11,7 @@ //! use axum::{ //! Json, //! handler::{post, Handler}, -//! route, +//! Router, //! }; //! use serde::Deserialize; //! @@ -27,7 +27,7 @@ //! // ... //! } //! -//! let app = route("/users", post(create_user)); +//! let app = Router::new().route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; @@ -42,7 +42,7 @@ //! async_trait, //! extract::{FromRequest, RequestParts}, //! handler::get, -//! route, +//! Router, //! }; //! use http::{StatusCode, header::{HeaderValue, USER_AGENT}}; //! @@ -72,7 +72,7 @@ //! // ... //! } //! -//! let app = route("/foo", get(handler)); +//! let app = Router::new().route("/foo", get(handler)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; @@ -86,7 +86,7 @@ //! use axum::{ //! extract::{Path, Query}, //! handler::get, -//! route, +//! Router, //! }; //! use std::collections::HashMap; //! @@ -101,7 +101,7 @@ //! // ... //! } //! -//! let app = route("/foo", get(handler)); +//! let app = Router::new().route("/foo", get(handler)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; @@ -118,7 +118,7 @@ //! use axum::{ //! extract::Json, //! handler::post, -//! route, +//! Router, //! }; //! use serde_json::Value; //! @@ -130,7 +130,7 @@ //! } //! } //! -//! let app = route("/users", post(create_user)); +//! let app = Router::new().route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; @@ -143,7 +143,7 @@ //! use axum::{ //! extract::{Json, rejection::JsonRejection}, //! handler::post, -//! route, +//! Router, //! }; //! use serde_json::Value; //! @@ -169,7 +169,7 @@ //! } //! } //! -//! let app = route("/users", post(create_user)); +//! let app = Router::new().route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; @@ -184,7 +184,7 @@ //! use axum::{ //! extract::Json, //! handler::post, -//! route, +//! Router, //! }; //! use serde_json::Value; //! @@ -192,7 +192,7 @@ //! // `value` is of type `Value` //! } //! -//! let app = route("/users", post(create_user)); +//! let app = Router::new().route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; @@ -217,7 +217,7 @@ //! body::Body, //! handler::get, //! http::{header::HeaderMap, Request}, -//! route, +//! Router, //! }; //! //! struct MyBody(B); @@ -244,10 +244,10 @@ //! } //! } //! -//! let app = -//! // `String` works directly with any body type -//! route( +//! let app = Router::new() +//! .route( //! "/string", +//! // `String` works directly with any body type //! get(|_: String| async {}) //! ) //! .route( diff --git a/src/extract/multipart.rs b/src/extract/multipart.rs index abe33774..75afed76 100644 --- a/src/extract/multipart.rs +++ b/src/extract/multipart.rs @@ -23,7 +23,7 @@ use tower::BoxError; /// use axum::{ /// extract::Multipart, /// handler::post, -/// route, +/// Router, /// }; /// use futures::stream::StreamExt; /// @@ -36,7 +36,7 @@ use tower::BoxError; /// } /// } /// -/// let app = route("/upload", post(upload)); +/// let app = Router::new().route("/upload", post(upload)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/extract/path/mod.rs b/src/extract/path/mod.rs index f8f2d1ff..6c558658 100644 --- a/src/extract/path/mod.rs +++ b/src/extract/path/mod.rs @@ -14,7 +14,7 @@ use std::ops::{Deref, DerefMut}; /// use axum::{ /// extract::Path, /// handler::get, -/// route, +/// Router, /// }; /// use uuid::Uuid; /// @@ -24,7 +24,7 @@ use std::ops::{Deref, DerefMut}; /// // ... /// } /// -/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show)); +/// let app = Router::new().route("/users/:user_id/team/:team_id", get(users_teams_show)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -36,7 +36,7 @@ use std::ops::{Deref, DerefMut}; /// use axum::{ /// extract::Path, /// handler::get, -/// route, +/// Router, /// }; /// use uuid::Uuid; /// @@ -44,7 +44,7 @@ use std::ops::{Deref, DerefMut}; /// // ... /// } /// -/// let app = route("/users/:user_id", get(user_info)); +/// let app = Router::new().route("/users/:user_id", get(user_info)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -57,7 +57,7 @@ use std::ops::{Deref, DerefMut}; /// use axum::{ /// extract::Path, /// handler::get, -/// route, +/// Router, /// }; /// use serde::Deserialize; /// use uuid::Uuid; @@ -74,7 +74,7 @@ use std::ops::{Deref, DerefMut}; /// // ... /// } /// -/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show)); +/// let app = Router::new().route("/users/:user_id/team/:team_id", get(users_teams_show)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/extract/query.rs b/src/extract/query.rs index 074596d3..975f9f85 100644 --- a/src/extract/query.rs +++ b/src/extract/query.rs @@ -13,7 +13,7 @@ use std::ops::Deref; /// use axum::{ /// extract::Query, /// handler::get, -/// route, +/// Router, /// }; /// use serde::Deserialize; /// @@ -31,7 +31,7 @@ use std::ops::Deref; /// // ... /// } /// -/// let app = route("/list_things", get(list_things)); +/// let app = Router::new().route("/list_things", get(list_things)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/extract/raw_query.rs b/src/extract/raw_query.rs index f64985a0..b802a675 100644 --- a/src/extract/raw_query.rs +++ b/src/extract/raw_query.rs @@ -10,7 +10,7 @@ use std::convert::Infallible; /// use axum::{ /// extract::RawQuery, /// handler::get, -/// route, +/// Router, /// }; /// use futures::StreamExt; /// @@ -18,7 +18,7 @@ use std::convert::Infallible; /// // ... /// } /// -/// let app = route("/users", get(handler)); +/// let app = Router::new().route("/users", get(handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/extract/request_parts.rs b/src/extract/request_parts.rs index 529c10f1..26a53999 100644 --- a/src/extract/request_parts.rs +++ b/src/extract/request_parts.rs @@ -92,21 +92,21 @@ where /// ``` /// use axum::{ /// handler::get, -/// route, -/// routing::nest, +/// Router, /// extract::OriginalUri, /// http::Uri /// }; /// -/// let api_routes = route( -/// "/users", -/// get(|uri: Uri, OriginalUri(original_uri): OriginalUri| async { -/// // `uri` is `/users` -/// // `original_uri` is `/api/users` -/// }), -/// ); +/// let api_routes = Router::new() +/// .route( +/// "/users", +/// get(|uri: Uri, OriginalUri(original_uri): OriginalUri| async { +/// // `uri` is `/users` +/// // `original_uri` is `/api/users` +/// }), +/// ); /// -/// let app = nest("/api", api_routes); +/// let app = Router::new().nest("/api", api_routes); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -174,7 +174,7 @@ where /// use axum::{ /// extract::BodyStream, /// handler::get, -/// route, +/// Router, /// }; /// use futures::StreamExt; /// @@ -184,7 +184,7 @@ where /// } /// } /// -/// let app = route("/users", get(handler)); +/// let app = Router::new().route("/users", get(handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -227,7 +227,7 @@ where /// use axum::{ /// extract::Body, /// handler::get, -/// route, +/// Router, /// }; /// use futures::StreamExt; /// @@ -235,7 +235,7 @@ where /// // ... /// } /// -/// let app = route("/users", get(handler)); +/// let app = Router::new().route("/users", get(handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -289,14 +289,14 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{body::Body, handler::post, route, tests::*}; + use crate::{body::Body, handler::post, tests::*, Router}; use http::StatusCode; #[tokio::test] async fn multiple_request_extractors() { async fn handler(_: Request, _: Request) {} - let app = route("/", post(handler)); + let app = Router::new().route("/", post(handler)); let addr = run_in_background(app).await; diff --git a/src/extract/typed_header.rs b/src/extract/typed_header.rs index 2ce2c6bf..40b5c673 100644 --- a/src/extract/typed_header.rs +++ b/src/extract/typed_header.rs @@ -14,7 +14,7 @@ use std::{convert::Infallible, ops::Deref}; /// use axum::{ /// extract::TypedHeader, /// handler::get, -/// route, +/// Router, /// }; /// use headers::UserAgent; /// @@ -24,7 +24,7 @@ use std::{convert::Infallible, ops::Deref}; /// // ... /// } /// -/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show)); +/// let app = Router::new().route("/users/:user_id/team/:team_id", get(users_teams_show)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -125,7 +125,7 @@ impl std::error::Error for TypedHeaderRejection { #[cfg(test)] mod tests { use super::*; - use crate::{handler::get, response::IntoResponse, route, tests::*}; + use crate::{handler::get, response::IntoResponse, tests::*, Router}; #[tokio::test] async fn typed_header() { @@ -135,7 +135,7 @@ mod tests { user_agent.to_string() } - let app = route("/", get(handle)); + let app = Router::new().route("/", get(handle)); let addr = run_in_background(app).await; diff --git a/src/extract/ws.rs b/src/extract/ws.rs index f95e5251..8bdcb7b7 100644 --- a/src/extract/ws.rs +++ b/src/extract/ws.rs @@ -7,10 +7,10 @@ //! extract::ws::{WebSocketUpgrade, WebSocket}, //! handler::get, //! response::IntoResponse, -//! route, +//! Router, //! }; //! -//! let app = route("/ws", get(handler)); +//! let app = Router::new().route("/ws", get(handler)); //! //! async fn handler(ws: WebSocketUpgrade) -> impl IntoResponse { //! ws.on_upgrade(handle_socket) @@ -113,10 +113,10 @@ impl WebSocketUpgrade { /// extract::ws::{WebSocketUpgrade, WebSocket}, /// handler::get, /// response::IntoResponse, - /// route, + /// Router, /// }; /// - /// let app = route("/ws", get(handler)); + /// let app = Router::new().route("/ws", get(handler)); /// /// async fn handler(ws: WebSocketUpgrade) -> impl IntoResponse { /// ws.protocols(["graphql-ws", "graphql-transport-ws"]) diff --git a/src/handler/mod.rs b/src/handler/mod.rs index e7d5e2c6..8fb0630c 100644 --- a/src/handler/mod.rs +++ b/src/handler/mod.rs @@ -33,13 +33,13 @@ pub use self::into_service::IntoService; /// ```rust /// use axum::{ /// handler::any, -/// route, +/// Router, /// }; /// /// async fn handler() {} /// /// // All requests to `/` will go to `handler` regardless of the HTTP method. -/// let app = route("/", any(handler)); +/// let app = Router::new().route("/", any(handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -78,13 +78,13 @@ where /// ```rust /// use axum::{ /// handler::get, -/// route, +/// Router, /// }; /// /// async fn handler() {} /// /// // Requests to `GET /` will go to `handler`. -/// let app = route("/", get(handler)); +/// let app = Router::new().route("/", get(handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -167,14 +167,14 @@ where /// ```rust /// use axum::{ /// handler::on, -/// route, +/// Router, /// routing::MethodFilter, /// }; /// /// async fn handler() {} /// /// // Requests to `POST /` will go to `handler`. -/// let app = route("/", on(MethodFilter::POST, handler)); +/// let app = Router::new().route("/", on(MethodFilter::POST, handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -234,14 +234,14 @@ pub trait Handler: Clone + Send + Sized + 'static { /// ```rust /// use axum::{ /// handler::{get, Handler}, - /// route, + /// Router, /// }; /// use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit}; /// /// async fn handler() { /* ... */ } /// /// let layered_handler = handler.layer(ConcurrencyLimitLayer::new(64)); - /// let app = route("/", get(layered_handler)); + /// let app = Router::new().route("/", get(layered_handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -511,7 +511,7 @@ impl OnMethod { /// # Example /// /// ```rust - /// use axum::{handler::post, route}; + /// use axum::{handler::post, Router}; /// /// async fn handler() {} /// @@ -519,7 +519,7 @@ impl OnMethod { /// /// // Requests to `GET /` will go to `handler` and `POST /` will go to /// // `other_handler`. - /// let app = route("/", post(handler).get(other_handler)); + /// let app = Router::new().route("/", post(handler).get(other_handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -603,7 +603,7 @@ impl OnMethod { /// ```rust /// use axum::{ /// handler::get, - /// route, + /// Router, /// routing::MethodFilter /// }; /// @@ -613,7 +613,7 @@ impl OnMethod { /// /// // Requests to `GET /` will go to `handler` and `DELETE /` will go to /// // `other_handler` - /// let app = route("/", get(handler).on(MethodFilter::DELETE, other_handler)); + /// let app = Router::new().route("/", get(handler).on(MethodFilter::DELETE, other_handler)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/json.rs b/src/json.rs index a4a5f80d..693ee8b4 100644 --- a/src/json.rs +++ b/src/json.rs @@ -30,7 +30,7 @@ use tower::BoxError; /// use axum::{ /// extract, /// handler::post, -/// route, +/// Router, /// }; /// use serde::Deserialize; /// @@ -44,7 +44,7 @@ use tower::BoxError; /// // payload is a `CreateUser` /// } /// -/// let app = route("/users", post(create_user)); +/// let app = Router::new().route("/users", post(create_user)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -59,7 +59,7 @@ use tower::BoxError; /// use axum::{ /// extract::Path, /// handler::get, -/// route, +/// Router, /// Json, /// }; /// use serde::Serialize; @@ -81,7 +81,7 @@ use tower::BoxError; /// # unimplemented!() /// } /// -/// let app = route("/users/:id", get(get_user)); +/// let app = Router::new().route("/users/:id", get(get_user)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/lib.rs b/src/lib.rs index 42576084..bb6e17ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,13 +48,13 @@ //! ```rust,no_run //! use axum::{ //! handler::get, -//! route, +//! Router, //! }; //! //! #[tokio::main] //! async fn main() { //! // build our application with a single route -//! let app = route("/", get(|| async { "Hello, World!" })); +//! let app = Router::new().route("/", get(|| async { "Hello, World!" })); //! //! // run it with hyper on localhost:3000 //! axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) @@ -105,10 +105,11 @@ //! ```rust,no_run //! use axum::{ //! handler::get, -//! route, +//! Router, //! }; //! -//! let app = route("/", get(get_slash).post(post_slash)) +//! let app = Router::new() +//! .route("/", get(get_slash).post(post_slash)) //! .route("/foo", get(get_foo)); //! //! async fn get_slash() { @@ -142,7 +143,7 @@ //! body::{Body, BoxBody}, //! handler::get, //! http::Request, -//! route, +//! Router, //! }; //! use tower::{Service, ServiceExt}; //! use http::{Method, Response, StatusCode}; @@ -152,7 +153,8 @@ //! # async fn main() { //! // `/foo` also matches `/:key` so adding the routes in this order means `/foo` //! // will be inaccessible. -//! let mut app = route("/foo", get(|| async { "/foo called" })) +//! let mut app = Router::new() +//! .route("/foo", get(|| async { "/foo called" })) //! .route("/:key", get(|| async { "/:key called" })); //! //! // Even though we use `/foo` as the request URI, `/:key` takes precedence @@ -163,7 +165,8 @@ //! //! // We have to add `/foo` after `/:key` since routes are matched bottom to //! // top. -//! let mut new_app = route("/:key", get(|| async { "/:key called" })) +//! let mut new_app = Router::new() +//! .route("/:key", get(|| async { "/:key called" })) //! .route("/foo", get(|| async { "/foo called" })); //! //! // Now it works @@ -207,15 +210,15 @@ //! //! ```rust,no_run //! use axum::{ -//! route, +//! Router, //! handler::{get, post}, //! }; //! //! // `GET /` and `POST /` are both accepted -//! let app = route("/", get(handler).post(handler)); +//! let app = Router::new().route("/", get(handler).post(handler)); //! //! // This will _not_ work. Only `POST /` will be accessible. -//! let wont_work = route("/", get(handler)).route("/", post(handler)); +//! let wont_work = Router::new().route("/", get(handler)).route("/", post(handler)); //! //! async fn handler() {} //! # async { @@ -232,7 +235,7 @@ //! use axum::{ //! body::Body, //! http::Request, -//! route, +//! Router, //! service //! }; //! use tower_http::services::ServeFile; @@ -240,31 +243,34 @@ //! use std::convert::Infallible; //! use tower::service_fn; //! -//! let app = route( -//! // Any request to `/` goes to a service -//! "/", -//! // Services who's response body is not `axum::body::BoxBody` -//! // can be wrapped in `axum::service::any` (or one of the other routing filters) -//! // to have the response body mapped -//! service::any(service_fn(|_: Request| async { -//! let res = Response::new(Body::from("Hi from `GET /`")); -//! Ok(res) -//! })) -//! ).route( -//! "/foo", -//! // This service's response body is `axum::body::BoxBody` so -//! // it can be routed to directly. -//! service_fn(|req: Request| async move { -//! let body = Body::from(format!("Hi from `{} /foo`", req.method())); -//! let body = axum::body::box_body(body); -//! let res = Response::new(body); -//! Ok(res) -//! }) -//! ).route( -//! // GET `/static/Cargo.toml` goes to a service from tower-http -//! "/static/Cargo.toml", -//! service::get(ServeFile::new("Cargo.toml")) -//! ); +//! let app = Router::new() +//! .route( +//! // Any request to `/` goes to a service +//! "/", +//! // Services who's response body is not `axum::body::BoxBody` +//! // can be wrapped in `axum::service::any` (or one of the other routing filters) +//! // to have the response body mapped +//! service::any(service_fn(|_: Request| async { +//! let res = Response::new(Body::from("Hi from `GET /`")); +//! Ok(res) +//! })) +//! ) +//! .route( +//! "/foo", +//! // This service's response body is `axum::body::BoxBody` so +//! // it can be routed to directly. +//! service_fn(|req: Request| async move { +//! let body = Body::from(format!("Hi from `{} /foo`", req.method())); +//! let body = axum::body::box_body(body); +//! let res = Response::new(body); +//! Ok(res) +//! }) +//! ) +//! .route( +//! // GET `/static/Cargo.toml` goes to a service from tower-http +//! "/static/Cargo.toml", +//! service::get(ServeFile::new("Cargo.toml")) +//! ); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; @@ -275,24 +281,27 @@ //! //! ## Nesting Routes //! -//! Routes can be nested by calling [`nest`](routing::nest): +//! Routes can be nested by calling [`Router::nest`](routing::Router::nest): //! //! ```rust,no_run //! use axum::{ //! body::{Body, BoxBody}, //! http::Request, //! handler::get, -//! route, -//! routing::{BoxRoute, Router} +//! Router, +//! routing::BoxRoute //! }; //! use tower_http::services::ServeFile; //! use http::Response; //! //! fn api_routes() -> Router { -//! route("/users", get(|_: Request| async { /* ... */ })).boxed() +//! Router::new() +//! .route("/users", get(|_: Request| async { /* ... */ })) +//! .boxed() //! } //! -//! let app = route("/", get(|_: Request| async { /* ... */ })) +//! let app = Router::new() +//! .route("/", get(|_: Request| async { /* ... */ })) //! .nest("/api", api_routes()); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); @@ -316,11 +325,11 @@ //! use axum::{ //! extract, //! handler::post, -//! route, +//! Router, //! }; //! use serde::Deserialize; //! -//! let app = route("/users", post(create_user)); +//! let app = Router::new().route("/users", post(create_user)); //! //! #[derive(Deserialize)] //! struct CreateUser { @@ -346,11 +355,11 @@ //! use axum::{ //! extract, //! handler::post, -//! route, +//! Router, //! }; //! use uuid::Uuid; //! -//! let app = route("/users/:id", post(create_user)); +//! let app = Router::new().route("/users/:id", post(create_user)); //! //! async fn create_user(extract::Path(user_id): extract::Path) { //! // ... @@ -366,12 +375,12 @@ //! use axum::{ //! extract, //! handler::get, -//! route, +//! Router, //! }; //! use uuid::Uuid; //! use serde::Deserialize; //! -//! let app = route("/users/:id/things", get(get_user_things)); +//! let app = Router::new().route("/users/:id/things", get(get_user_things)); //! //! #[derive(Deserialize)] //! struct Pagination { @@ -405,10 +414,10 @@ //! body::Body, //! handler::post, //! http::Request, -//! route, +//! Router, //! }; //! -//! let app = route("/users/:id", post(handler)); +//! let app = Router::new().route("/users/:id", post(handler)); //! //! async fn handler(req: Request) { //! // ... @@ -437,7 +446,7 @@ //! handler::{get, Handler}, //! http::Request, //! response::{Html, Json}, -//! route, +//! Router, //! }; //! use http::{StatusCode, Response, Uri}; //! use serde_json::{Value, json}; @@ -493,7 +502,8 @@ //! Response::builder().body(Body::empty()).unwrap() //! } //! -//! let app = route("/plain_text", get(plain_text)) +//! let app = Router::new() +//! .route("/plain_text", get(plain_text)) //! .route("/plain_text_string", get(plain_text_string)) //! .route("/bytes", get(bytes)) //! .route("/empty", get(empty)) @@ -520,14 +530,15 @@ //! ```rust,no_run //! use axum::{ //! handler::{get, Handler}, -//! route, +//! Router, //! }; //! use tower::limit::ConcurrencyLimitLayer; //! -//! let app = route( -//! "/", -//! get(handler.layer(ConcurrencyLimitLayer::new(100))), -//! ); +//! let app = Router::new() +//! .route( +//! "/", +//! get(handler.layer(ConcurrencyLimitLayer::new(100))), +//! ); //! //! async fn handler() {} //! # async { @@ -542,11 +553,12 @@ //! ```rust,no_run //! use axum::{ //! handler::{get, post}, -//! route, +//! Router, //! }; //! use tower::limit::ConcurrencyLimitLayer; //! -//! let app = route("/", get(get_slash)) +//! let app = Router::new() +//! .route("/", get(get_slash)) //! .route("/foo", post(post_foo)) //! .layer(ConcurrencyLimitLayer::new(100)); //! @@ -575,7 +587,7 @@ //! ```rust,no_run //! use axum::{ //! handler::{get, Handler}, -//! route, +//! Router, //! }; //! use tower::{ //! BoxError, timeout::{TimeoutLayer, error::Elapsed}, @@ -583,30 +595,31 @@ //! use std::{borrow::Cow, time::Duration, convert::Infallible}; //! use http::StatusCode; //! -//! let app = route( -//! "/", -//! get(handle -//! .layer(TimeoutLayer::new(Duration::from_secs(30))) -//! // `Timeout` uses `BoxError` as the error type -//! .handle_error(|error: BoxError| { -//! // Check if the actual error type is `Elapsed` which -//! // `Timeout` returns -//! if error.is::() { -//! return Ok::<_, Infallible>(( -//! StatusCode::REQUEST_TIMEOUT, -//! "Request took too long".into(), -//! )); -//! } +//! let app = Router::new() +//! .route( +//! "/", +//! get(handle +//! .layer(TimeoutLayer::new(Duration::from_secs(30))) +//! // `Timeout` uses `BoxError` as the error type +//! .handle_error(|error: BoxError| { +//! // Check if the actual error type is `Elapsed` which +//! // `Timeout` returns +//! if error.is::() { +//! return Ok::<_, Infallible>(( +//! StatusCode::REQUEST_TIMEOUT, +//! "Request took too long".into(), +//! )); +//! } //! -//! // If we encounter some error we don't handle return a generic -//! // error -//! return Ok::<_, Infallible>(( -//! StatusCode::INTERNAL_SERVER_ERROR, -//! // `Cow` lets us return either `&str` or `String` -//! Cow::from(format!("Unhandled internal error: {}", error)), -//! )); -//! })), -//! ); +//! // If we encounter some error we don't handle return a generic +//! // error +//! return Ok::<_, Infallible>(( +//! StatusCode::INTERNAL_SERVER_ERROR, +//! // `Cow` lets us return either `&str` or `String` +//! Cow::from(format!("Unhandled internal error: {}", error)), +//! )); +//! })), +//! ); //! //! async fn handle() {} //! # async { @@ -629,7 +642,7 @@ //! body::Body, //! handler::get, //! http::Request, -//! route, +//! Router, //! }; //! use tower::ServiceBuilder; //! use tower_http::compression::CompressionLayer; @@ -646,7 +659,8 @@ //! .layer(CompressionLayer::new()) //! .into_inner(); //! -//! let app = route("/", get(|_: Request| async { /* ... */ })) +//! let app = Router::new() +//! .route("/", get(|_: Request| async { /* ... */ })) //! .layer(middleware_stack); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); @@ -665,7 +679,7 @@ //! AddExtensionLayer, //! extract, //! handler::get, -//! route, +//! Router, //! }; //! use std::sync::Arc; //! @@ -675,7 +689,9 @@ //! //! let shared_state = Arc::new(State { /* ... */ }); //! -//! let app = route("/", get(handler)).layer(AddExtensionLayer::new(shared_state)); +//! let app = Router::new() +//! .route("/", get(handler)) +//! .layer(AddExtensionLayer::new(shared_state)); //! //! async fn handler( //! state: extract::Extension>, @@ -738,6 +754,8 @@ //! [`Router::or`]: crate::routing::Router::or //! [`axum::Server`]: hyper::server::Server //! [`OriginalUri`]: crate::extract::OriginalUri +//! [`Service`]: tower::Service +//! [`Service::poll_ready`]: tower::Service::poll_ready #![warn( clippy::all, @@ -779,10 +797,6 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(test, allow(clippy::float_cmp))] -use http::Request; -use routing::{EmptyRouter, Route}; -use tower::Service; - #[macro_use] pub(crate) mod macros; @@ -810,56 +824,4 @@ pub use hyper::Server; #[doc(no_inline)] pub use tower_http::add_extension::{AddExtension, AddExtensionLayer}; -pub use self::{error::Error, json::Json}; - -/// Create a route. -/// -/// `description` is a string of path segments separated by `/`. Each segment -/// can be either concrete or a capture: -/// -/// - `/foo/bar/baz` will only match requests where the path is `/foo/bar/bar`. -/// - `/:foo` will match any route with exactly one segment _and_ it will -/// capture the first segment and store it at the key `foo`. -/// -/// `service` is the [`Service`] that should receive the request if the path -/// matches `description`. -/// -/// # Examples -/// -/// ```rust -/// use axum::{ -/// body::Body, -/// http::Request, -/// route -/// }; -/// -/// # use std::convert::Infallible; -/// # use http::Response; -/// # let service = tower::service_fn(|_: Request| async { -/// # Ok::, Infallible>(Response::new(Body::empty())) -/// # }); -/// -/// route("/", service); -/// route("/users", service); -/// route("/users/:id", service); -/// route("/api/:version/users/:id/action", service); -/// ``` -/// -/// # Panics -/// -/// Panics if `description` doesn't start with `/`. -pub fn route( - description: &str, - service: S, -) -> routing::Router>> -where - S: Service> + Clone, -{ - routing::Router::new().route(description, service) -} - -mod sealed { - #![allow(unreachable_pub, missing_docs)] - - pub trait Sealed {} -} +pub use self::{error::Error, json::Json, routing::Router}; diff --git a/src/response/headers.rs b/src/response/headers.rs index c492f369..812c97cd 100644 --- a/src/response/headers.rs +++ b/src/response/headers.rs @@ -13,7 +13,7 @@ use tower::{util::Either, BoxError}; /// /// ```rust /// use axum::{ -/// route, +/// Router, /// response::{IntoResponse, Headers}, /// handler::get, /// }; @@ -36,7 +36,8 @@ use tower::{util::Either, BoxError}; /// /// // Or `[(&str, &str)]` if you're on Rust 1.53+ /// -/// let app = route("/just-headers", get(just_headers)) +/// let app = Router::new() +/// .route("/just-headers", get(just_headers)) /// .route("/from-strings", get(from_strings)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); diff --git a/src/response/mod.rs b/src/response/mod.rs index 2bbb8ae8..584cefb5 100644 --- a/src/response/mod.rs +++ b/src/response/mod.rs @@ -44,7 +44,7 @@ pub use self::{ /// use axum::{ /// handler::get, /// response::IntoResponse, -/// route, +/// Router, /// }; /// use http_body::Body; /// use http::{Response, HeaderMap}; @@ -94,7 +94,7 @@ pub use self::{ /// // covered by a blanket implementation in axum. /// /// // `MyBody` can now be returned from handlers. -/// let app = route("/", get(|| async { MyBody })); +/// let app = Router::new().route("/", get(|| async { MyBody })); /// # async { /// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/response/redirect.rs b/src/response/redirect.rs index 3c7eaabd..e6139893 100644 --- a/src/response/redirect.rs +++ b/src/response/redirect.rs @@ -12,10 +12,11 @@ use std::convert::TryFrom; /// use axum::{ /// handler::get, /// response::Redirect, -/// route, +/// Router, /// }; /// -/// let app = route("/old", get(|| async { Redirect::permanent("/new".parse().unwrap()) })) +/// let app = Router::new() +/// .route("/old", get(|| async { Redirect::permanent("/new".parse().unwrap()) })) /// .route("/new", get(|| async { "Hello!" })); /// # async { /// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); diff --git a/src/response/sse.rs b/src/response/sse.rs index 2577aca6..4a069971 100644 --- a/src/response/sse.rs +++ b/src/response/sse.rs @@ -5,14 +5,14 @@ //! ``` //! use axum::{ //! handler::get, -//! route, +//! Router, //! }; //! use axum::response::sse::{sse, Event, KeepAlive, Sse}; //! use std::{time::Duration, convert::Infallible}; //! use tokio_stream::StreamExt as _ ; //! use futures::stream::{self, Stream}; //! -//! let app = route("/sse", get(sse_handler)); +//! let app = Router::new().route("/sse", get(sse_handler)); //! //! async fn sse_handler() -> Sse>> { //! // A `Stream` that repeats an event every second diff --git a/src/routing/mod.rs b/src/routing/mod.rs index 2e2bc315..eb2ffc91 100644 --- a/src/routing/mod.rs +++ b/src/routing/mod.rs @@ -81,28 +81,44 @@ where impl Router { /// Add another route to the router. /// + /// `description` is a string of path segments separated by `/`. Each segment + /// can be either concrete or a capture: + /// + /// - `/foo/bar/baz` will only match requests where the path is `/foo/bar/bar`. + /// - `/:foo` will match any route with exactly one segment _and_ it will + /// capture the first segment and store it at the key `foo`. + /// + /// `service` is the [`Service`] that should receive the request if the path + /// matches `description`. + /// /// # Example /// /// ```rust - /// use axum::{ - /// handler::get, - /// route, - /// }; + /// use axum::{handler::{get, delete}, Router}; /// - /// async fn first_handler() { /* ... */ } + /// let app = Router::new() + /// .route("/", get(root)) + /// .route("/users", get(list_users).post(create_user)) + /// .route("/users/:id", get(show_user)) + /// .route("/api/:version/users/:id/action", delete(do_thing)); /// - /// async fn second_handler() { /* ... */ } + /// async fn root() { /* ... */ } /// - /// async fn third_handler() { /* ... */ } + /// async fn list_users() { /* ... */ } /// - /// // `GET /` goes to `first_handler`, `POST /` goes to `second_handler`, - /// // and `GET /foo` goes to third_handler. - /// let app = route("/", get(first_handler).post(second_handler)) - /// .route("/foo", get(third_handler)); + /// async fn create_user() { /* ... */ } + /// + /// async fn show_user() { /* ... */ } + /// + /// async fn do_thing() { /* ... */ } /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; /// ``` + /// + /// # Panics + /// + /// Panics if `description` doesn't start with `/`. pub fn route(self, description: &str, svc: T) -> Router> where T: Service> + Clone, @@ -114,9 +130,83 @@ impl Router { }) } - /// Nest another service inside this router at the given path. + /// Nest a group of routes (or a [`Service`]) at some path. /// - /// See [`nest`] for more details. + /// This allows you to break your application into smaller pieces and compose + /// them together. + /// + /// ``` + /// use axum::{ + /// handler::get, + /// Router, + /// }; + /// use http::Uri; + /// + /// async fn users_get(uri: Uri) { + /// // `users_get` will still see the whole URI. + /// assert_eq!(uri.path(), "/api/users"); + /// } + /// + /// async fn users_post() {} + /// + /// async fn careers() {} + /// + /// let users_api = Router::new().route("/users", get(users_get).post(users_post)); + /// + /// let app = Router::new().nest("/api", users_api).route("/careers", get(careers)); + /// # async { + /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); + /// # }; + /// ``` + /// + /// Take care when using `nest` together with dynamic routes as nesting also + /// captures from the outer routes: + /// + /// ``` + /// use axum::{ + /// extract::Path, + /// handler::get, + /// Router, + /// }; + /// use std::collections::HashMap; + /// + /// async fn users_get(Path(params): Path>) { + /// // Both `version` and `id` were captured even though `users_api` only + /// // explicitly captures `id`. + /// let version = params.get("version"); + /// let id = params.get("id"); + /// } + /// + /// let users_api = Router::new().route("/users/:id", get(users_get)); + /// + /// let app = Router::new().nest("/:version/api", users_api); + /// # async { + /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); + /// # }; + /// ``` + /// + /// `nest` also accepts any [`Service`]. This can for example be used with + /// [`tower_http::services::ServeDir`] to serve static files from a directory: + /// + /// ``` + /// use axum::{ + /// Router, + /// service::get, + /// }; + /// use tower_http::services::ServeDir; + /// + /// // Serves files inside the `public` directory at `GET /public/*` + /// let serve_dir_service = ServeDir::new("public"); + /// + /// let app = Router::new().nest("/public", get(serve_dir_service)); + /// # async { + /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); + /// # }; + /// ``` + /// + /// If necessary you can use [`Router::boxed`] to box a group of routes + /// making the type easier to name. This is sometimes useful when working with + /// `nest`. pub fn nest(self, description: &str, svc: T) -> Router> where T: Service> + Clone, @@ -137,8 +227,8 @@ impl Router { /// use axum::{ /// body::Body, /// handler::get, - /// route, - /// routing::{Router, BoxRoute} + /// Router, + /// routing::BoxRoute /// }; /// /// async fn first_handler() { /* ... */ } @@ -148,7 +238,8 @@ impl Router { /// async fn third_handler() { /* ... */ } /// /// fn app() -> Router { - /// route("/", get(first_handler).post(second_handler)) + /// Router::new() + /// .route("/", get(first_handler).post(second_handler)) /// .route("/foo", get(third_handler)) /// .boxed() /// } @@ -195,7 +286,7 @@ impl Router { /// ```rust /// use axum::{ /// handler::get, - /// route, + /// Router, /// }; /// use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit}; /// @@ -207,7 +298,7 @@ impl Router { /// /// // All requests to `handler` and `other_handler` will be sent through /// // `ConcurrencyLimit` - /// let app = route("/", get(first_handler)) + /// let app = Router::new().route("/", get(first_handler)) /// .route("/foo", get(second_handler)) /// .layer(ConcurrencyLimitLayer::new(64)) /// // Request to `GET /bar` will go directly to `third_handler` and @@ -224,7 +315,7 @@ impl Router { /// ```rust /// use axum::{ /// handler::get, - /// route, + /// Router, /// }; /// use tower_http::trace::TraceLayer; /// @@ -234,7 +325,8 @@ impl Router { /// /// async fn third_handler() { /* ... */ } /// - /// let app = route("/", get(first_handler)) + /// let app = Router::new() + /// .route("/", get(first_handler)) /// .route("/foo", get(second_handler)) /// .route("/bar", get(third_handler)) /// .layer(TraceLayer::new_for_http()); @@ -258,10 +350,10 @@ impl Router { /// ``` /// use axum::{ /// handler::get, - /// route, + /// Router, /// }; /// - /// let app = route("/", get(|| async { "Hi!" })); + /// let app = Router::new().route("/", get(|| async { "Hi!" })); /// /// # async { /// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) @@ -291,11 +383,11 @@ impl Router { /// use axum::{ /// extract::ConnectInfo, /// handler::get, - /// route, + /// Router, /// }; /// use std::net::SocketAddr; /// - /// let app = route("/", get(handler)); + /// let app = Router::new().route("/", get(handler)); /// /// async fn handler(ConnectInfo(addr): ConnectInfo) -> String { /// format!("Hello {}", addr) @@ -317,11 +409,11 @@ impl Router { /// use axum::{ /// extract::connect_info::{ConnectInfo, Connected}, /// handler::get, - /// route, + /// Router, /// }; /// use hyper::server::conn::AddrStream; /// - /// let app = route("/", get(handler)); + /// let app = Router::new().route("/", get(handler)); /// /// async fn handler( /// ConnectInfo(my_connect_info): ConnectInfo, @@ -379,7 +471,7 @@ impl Router { /// ``` /// use axum::{ /// handler::get, - /// route, + /// Router, /// }; /// # /// # async fn users_list() {} @@ -387,10 +479,10 @@ impl Router { /// # async fn teams_list() {} /// /// // define some routes separately - /// let user_routes = route("/users", get(users_list)) + /// let user_routes = Router::new().route("/users", get(users_list)) /// .route("/users/:id", get(users_show)); /// - /// let team_routes = route("/teams", get(teams_list)); + /// let team_routes = Router::new().route("/teams", get(teams_list)); /// /// // combine them into one /// let app = user_routes.or(team_routes); @@ -416,13 +508,13 @@ impl Router { /// use axum::{ /// handler::get, /// http::StatusCode, - /// route, + /// Router, /// }; /// use tower::{BoxError, timeout::TimeoutLayer}; /// use std::{time::Duration, convert::Infallible}; /// /// // This router can never fail, since handlers can never fail. - /// let app = route("/", get(|| async {})); + /// let app = Router::new().route("/", get(|| async {})); /// /// // Now the router can fail since the `tower::timeout::Timeout` /// // middleware will return an error if the timeout elapses. @@ -455,12 +547,13 @@ impl Router { /// use axum::{ /// handler::get, /// http::StatusCode, - /// route, + /// Router, /// }; /// use tower::{BoxError, timeout::TimeoutLayer}; /// use std::time::Duration; /// - /// let app = route("/", get(|| async {})) + /// let app = Router::new() + /// .route("/", get(|| async {})) /// .layer(TimeoutLayer::new(Duration::from_secs(10))) /// .handle_error(|error: BoxError| { /// if error.is::() { @@ -498,8 +591,6 @@ impl Router { /// A route that sends requests to one of two [`Service`]s depending on the /// path. -/// -/// Created with [`route`](crate::route). See that function for more details. #[derive(Debug, Clone)] pub struct Route { pub(crate) pattern: PathPattern, @@ -845,95 +936,9 @@ where } } -/// Nest a group of routes (or a [`Service`]) at some path. -/// -/// This allows you to break your application into smaller pieces and compose -/// them together. -/// -/// ``` -/// use axum::{ -/// handler::get, -/// route, -/// routing::nest, -/// }; -/// use http::Uri; -/// -/// async fn users_get(uri: Uri) { -/// // `users_get` will still see the whole URI. -/// assert_eq!(uri.path(), "/api/users"); -/// } -/// -/// async fn users_post() {} -/// -/// async fn careers() {} -/// -/// let users_api = route("/users", get(users_get).post(users_post)); -/// -/// let app = nest("/api", users_api).route("/careers", get(careers)); -/// # async { -/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); -/// # }; -/// ``` -/// -/// Take care when using `nest` together with dynamic routes as nesting also -/// captures from the outer routes: -/// -/// ``` -/// use axum::{ -/// extract::Path, -/// handler::get, -/// route, -/// routing::nest, -/// }; -/// use std::collections::HashMap; -/// -/// async fn users_get(Path(params): Path>) { -/// // Both `version` and `id` were captured even though `users_api` only -/// // explicitly captures `id`. -/// let version = params.get("version"); -/// let id = params.get("id"); -/// } -/// -/// let users_api = route("/users/:id", get(users_get)); -/// -/// let app = nest("/:version/api", users_api); -/// # async { -/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); -/// # }; -/// ``` -/// -/// `nest` also accepts any [`Service`]. This can for example be used with -/// [`tower_http::services::ServeDir`] to serve static files from a directory: -/// -/// ``` -/// use axum::{ -/// routing::nest, -/// service::get, -/// }; -/// use tower_http::services::ServeDir; -/// -/// // Serves files inside the `public` directory at `GET /public/*` -/// let serve_dir_service = ServeDir::new("public"); -/// -/// let app = nest("/public", get(serve_dir_service)); -/// # async { -/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); -/// # }; -/// ``` -/// -/// If necessary you can use [`Router::boxed`] to box a group of routes -/// making the type easier to name. This is sometimes useful when working with -/// `nest`. -pub fn nest(description: &str, svc: S) -> Router>> -where - S: Service> + Clone, -{ - Router::new().nest(description, svc) -} - /// A [`Service`] that has been nested inside a router at some path. /// -/// Created with [`nest`] or [`Router::nest`]. +/// Created with [`Router::nest`]. #[derive(Debug, Clone)] pub struct Nested { pattern: PathPattern, diff --git a/src/service/mod.rs b/src/service/mod.rs index 1b54c48b..c8833a35 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -15,7 +15,7 @@ //! body::Body, //! handler::get, //! http::Request, -//! route, +//! Router, //! service, //! }; //! @@ -23,7 +23,8 @@ //! //! let redirect_service = Redirect::::permanent("/new".parse().unwrap()); //! -//! let app = route("/old", service::get(redirect_service)) +//! let app = Router::new() +//! .route("/old", service::get(redirect_service)) //! .route("/new", get(handler)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); @@ -66,7 +67,7 @@ //! ```rust //! use axum::{ //! handler::get, -//! route, +//! Router, //! }; //! use tower::ServiceBuilder; //! # let some_backpressure_sensitive_middleware = @@ -74,7 +75,7 @@ //! //! async fn handler() { /* ... */ } //! -//! let app = route("/", get(handler)); +//! let app = Router::new().route("/", get(handler)); //! //! let app = ServiceBuilder::new() //! .layer(some_backpressure_sensitive_middleware) @@ -148,7 +149,7 @@ where /// ```rust /// use axum::{ /// http::Request, -/// route, +/// Router, /// service, /// }; /// use http::Response; @@ -160,7 +161,7 @@ where /// }); /// /// // Requests to `GET /` will go to `service`. -/// let app = route("/", service::get(service)); +/// let app = Router::new().route("/", service::get(service)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -245,7 +246,7 @@ where /// http::Request, /// handler::on, /// service, -/// route, +/// Router, /// routing::MethodFilter, /// }; /// use http::Response; @@ -257,7 +258,7 @@ where /// }); /// /// // Requests to `POST /` will go to `service`. -/// let app = route("/", service::on(MethodFilter::POST, service)); +/// let app = Router::new().route("/", service::on(MethodFilter::POST, service)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -340,7 +341,7 @@ impl OnMethod { /// http::Request, /// handler::on, /// service, - /// route, + /// Router, /// routing::MethodFilter, /// }; /// use http::Response; @@ -357,7 +358,7 @@ impl OnMethod { /// /// // Requests to `GET /` will go to `service` and `POST /` will go to /// // `other_service`. - /// let app = route("/", service::post(service).get(other_service)); + /// let app = Router::new().route("/", service::post(service).get(other_service)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; @@ -443,7 +444,7 @@ impl OnMethod { /// http::Request, /// handler::on, /// service, - /// route, + /// Router, /// routing::MethodFilter, /// }; /// use http::Response; @@ -459,7 +460,7 @@ impl OnMethod { /// }); /// /// // Requests to `DELETE /` will go to `service` - /// let app = route("/", service::on(MethodFilter::DELETE, service)); + /// let app = Router::new().route("/", service::on(MethodFilter::DELETE, service)); /// # async { /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; diff --git a/src/tests/get_to_head.rs b/src/tests/get_to_head.rs index e436cd92..37b39e04 100644 --- a/src/tests/get_to_head.rs +++ b/src/tests/get_to_head.rs @@ -7,7 +7,7 @@ mod for_handlers { #[tokio::test] async fn get_handles_head() { - let app = route( + let app = Router::new().route( "/", get(|| async { let mut headers = HeaderMap::new(); @@ -43,7 +43,7 @@ mod for_services { #[tokio::test] async fn get_handles_head() { - let app = route( + let app = Router::new().route( "/", get(service_fn(|_req: Request| async move { let res = Response::builder() diff --git a/src/tests/handle_error.rs b/src/tests/handle_error.rs index cb9ea595..7bf907c8 100644 --- a/src/tests/handle_error.rs +++ b/src/tests/handle_error.rs @@ -41,7 +41,7 @@ fn handle_error(_: E) -> Result { #[tokio::test] async fn handler() { - let app = route( + let app = Router::new().route( "/", get(forever .layer(timeout()) @@ -62,7 +62,7 @@ async fn handler() { #[tokio::test] async fn handler_multiple_methods_first() { - let app = route( + let app = Router::new().route( "/", get(forever .layer(timeout()) @@ -84,7 +84,7 @@ async fn handler_multiple_methods_first() { #[tokio::test] async fn handler_multiple_methods_middle() { - let app = route( + let app = Router::new().route( "/", delete(unit) .get( @@ -109,7 +109,7 @@ async fn handler_multiple_methods_middle() { #[tokio::test] async fn handler_multiple_methods_last() { - let app = route( + let app = Router::new().route( "/", delete(unit).get( forever @@ -132,21 +132,22 @@ async fn handler_multiple_methods_last() { #[test] fn service_propagates_errors() { - let app = route::<_, Body>("/echo", service::post(Svc)); + let app = Router::new().route::<_, Body>("/echo", service::post(Svc)); check_make_svc::<_, _, _, hyper::Error>(app.into_make_service()); } #[test] fn service_nested_propagates_errors() { - let app = route::<_, Body>("/echo", nest("/foo", service::post(Svc))); + let app = + Router::new().route::<_, Body>("/echo", Router::new().nest("/foo", service::post(Svc))); check_make_svc::<_, _, _, hyper::Error>(app.into_make_service()); } #[test] fn service_handle_on_method() { - let app = route::<_, Body>( + let app = Router::new().route::<_, Body>( "/echo", service::get(Svc).handle_error(handle_error::), ); @@ -156,7 +157,7 @@ fn service_handle_on_method() { #[test] fn service_handle_on_method_multiple() { - let app = route::<_, Body>( + let app = Router::new().route::<_, Body>( "/echo", service::get(Svc) .post(Svc) @@ -168,15 +169,17 @@ fn service_handle_on_method_multiple() { #[test] fn service_handle_on_router() { - let app = - route::<_, Body>("/echo", service::get(Svc)).handle_error(handle_error::); + let app = Router::new() + .route::<_, Body>("/echo", service::get(Svc)) + .handle_error(handle_error::); check_make_svc::<_, _, _, Infallible>(app.into_make_service()); } #[test] fn service_handle_on_router_still_impls_routing_dsl() { - let app = route::<_, Body>("/echo", service::get(Svc)) + let app = Router::new() + .route::<_, Body>("/echo", service::get(Svc)) .handle_error(handle_error::) .route("/", get(unit)); @@ -185,7 +188,8 @@ fn service_handle_on_router_still_impls_routing_dsl() { #[test] fn layered() { - let app = route::<_, Body>("/echo", get(unit)) + let app = Router::new() + .route::<_, Body>("/echo", get(unit)) .layer(timeout()) .handle_error(handle_error::); @@ -194,7 +198,8 @@ fn layered() { #[tokio::test] // async because of `.boxed()` async fn layered_boxed() { - let app = route::<_, Body>("/echo", get(unit)) + let app = Router::new() + .route::<_, Body>("/echo", get(unit)) .layer(timeout()) .boxed() .handle_error(handle_error::); diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 3ea24cd4..b3d8478f 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -4,10 +4,8 @@ use crate::{ extract, handler::{any, delete, get, on, patch, post, Handler}, response::IntoResponse, - route, - routing::nest, routing::MethodFilter, - service, + service, Router, }; use bytes::Bytes; use futures_util::future::Ready; @@ -46,7 +44,9 @@ async fn hello_world() { "users#create" } - let app = route("/", get(root).post(foo)).route("/users", post(users_create)); + let app = Router::new() + .route("/", get(root).post(foo)) + .route("/users", post(users_create)); let addr = run_in_background(app).await; @@ -75,7 +75,7 @@ async fn hello_world() { #[tokio::test] async fn consume_body() { - let app = route("/", get(|body: String| async { body })); + let app = Router::new().route("/", get(|body: String| async { body })); let addr = run_in_background(app).await; @@ -98,7 +98,7 @@ async fn deserialize_body() { foo: String, } - let app = route( + let app = Router::new().route( "/", post(|input: extract::Json| async { input.0.foo }), ); @@ -124,7 +124,7 @@ async fn consume_body_to_json_requires_json_content_type() { foo: String, } - let app = route( + let app = Router::new().route( "/", post(|input: extract::Json| async { input.0.foo }), ); @@ -156,7 +156,7 @@ async fn body_with_length_limit() { const LIMIT: u64 = 8; - let app = route( + let app = Router::new().route( "/", post(|_body: extract::ContentLengthLimit| async {}), ); @@ -202,16 +202,17 @@ async fn body_with_length_limit() { #[tokio::test] async fn routing() { - let app = route( - "/users", - get(|_: Request| async { "users#index" }) - .post(|_: Request| async { "users#create" }), - ) - .route("/users/:id", get(|_: Request| async { "users#show" })) - .route( - "/users/:id/action", - get(|_: Request| async { "users#action" }), - ); + let app = Router::new() + .route( + "/users", + get(|_: Request| async { "users#index" }) + .post(|_: Request| async { "users#create" }), + ) + .route("/users/:id", get(|_: Request| async { "users#show" })) + .route( + "/users/:id/action", + get(|_: Request| async { "users#action" }), + ); let addr = run_in_background(app).await; @@ -255,7 +256,7 @@ async fn routing() { #[tokio::test] async fn extracting_url_params() { - let app = route( + let app = Router::new().route( "/users/:id", get(|extract::Path(id): extract::Path| async move { assert_eq!(id, 42); @@ -288,7 +289,7 @@ async fn extracting_url_params() { #[tokio::test] async fn extracting_url_params_multiple_times() { - let app = route( + let app = Router::new().route( "/users/:id", get(|_: extract::Path, _: extract::Path| async {}), ); @@ -307,17 +308,18 @@ async fn extracting_url_params_multiple_times() { #[tokio::test] async fn boxing() { - let app = route( - "/", - on(MethodFilter::GET, |_: Request| async { - "hi from GET" - }) - .on(MethodFilter::POST, |_: Request| async { - "hi from POST" - }), - ) - .layer(tower_http::compression::CompressionLayer::new()) - .boxed(); + let app = Router::new() + .route( + "/", + on(MethodFilter::GET, |_: Request| async { + "hi from GET" + }) + .on(MethodFilter::POST, |_: Request| async { + "hi from POST" + }), + ) + .layer(tower_http::compression::CompressionLayer::new()) + .boxed(); let addr = run_in_background(app).await; @@ -345,22 +347,23 @@ async fn routing_between_services() { "handler" } - let app = route( - "/one", - service::get(service_fn(|_: Request| async { - Ok::<_, Infallible>(Response::new(Body::from("one get"))) - })) - .post(service_fn(|_: Request| async { - Ok::<_, Infallible>(Response::new(Body::from("one post"))) - })) - .on( - MethodFilter::PUT, - service_fn(|_: Request| async { - Ok::<_, Infallible>(Response::new(Body::from("one put"))) - }), - ), - ) - .route("/two", service::on(MethodFilter::GET, any(handle))); + let app = Router::new() + .route( + "/one", + service::get(service_fn(|_: Request| async { + Ok::<_, Infallible>(Response::new(Body::from("one get"))) + })) + .post(service_fn(|_: Request| async { + Ok::<_, Infallible>(Response::new(Body::from("one post"))) + })) + .on( + MethodFilter::PUT, + service_fn(|_: Request| async { + Ok::<_, Infallible>(Response::new(Body::from("one put"))) + }), + ), + ) + .route("/two", service::on(MethodFilter::GET, any(handle))); let addr = run_in_background(app).await; @@ -408,7 +411,7 @@ async fn middleware_on_single_route() { "Hello, World!" } - let app = route( + let app = Router::new().route( "/", get(handle.layer( ServiceBuilder::new() @@ -432,7 +435,7 @@ async fn service_in_bottom() { Ok(Response::new(hyper::Body::empty())) } - let app = route("/", service::get(service_fn(handler))); + let app = Router::new().route("/", service::get(service_fn(handler))); run_in_background(app).await; } @@ -466,7 +469,7 @@ async fn test_extractor_middleware() { async fn handler() {} - let app = route( + let app = Router::new().route( "/", get(handler.layer(extract::extractor_middleware::())), ); @@ -493,7 +496,9 @@ async fn test_extractor_middleware() { #[tokio::test] async fn wrong_method_handler() { - let app = route("/", get(|| async {}).post(|| async {})).route("/foo", patch(|| async {})); + let app = Router::new() + .route("/", get(|| async {}).post(|| async {})) + .route("/foo", patch(|| async {})); let addr = run_in_background(app).await; @@ -547,7 +552,9 @@ async fn wrong_method_service() { } } - let app = route("/", service::get(Svc).post(Svc)).route("/foo", service::patch(Svc)); + let app = Router::new() + .route("/", service::get(Svc).post(Svc)) + .route("/foo", service::patch(Svc)); let addr = run_in_background(app).await; @@ -588,7 +595,7 @@ async fn multiple_methods_for_one_handler() { "Hello, World!" } - let app = route("/", on(MethodFilter::GET | MethodFilter::POST, root)); + let app = Router::new().route("/", on(MethodFilter::GET | MethodFilter::POST, root)); let addr = run_in_background(app).await; diff --git a/src/tests/nest.rs b/src/tests/nest.rs index 3bf8587c..fc8b4417 100644 --- a/src/tests/nest.rs +++ b/src/tests/nest.rs @@ -4,36 +4,39 @@ use std::collections::HashMap; #[tokio::test] async fn nesting_apps() { - let api_routes = route( - "/users", - get(|| async { "users#index" }).post(|| async { "users#create" }), - ) - .route( - "/users/:id", - get( - |params: extract::Path>| async move { - format!( - "{}: users#show ({})", - params.get("version").unwrap(), - params.get("id").unwrap() - ) - }, - ), - ) - .route( - "/games/:id", - get( - |params: extract::Path>| async move { - format!( - "{}: games#show ({})", - params.get("version").unwrap(), - params.get("id").unwrap() - ) - }, - ), - ); + let api_routes = Router::new() + .route( + "/users", + get(|| async { "users#index" }).post(|| async { "users#create" }), + ) + .route( + "/users/:id", + get( + |params: extract::Path>| async move { + format!( + "{}: users#show ({})", + params.get("version").unwrap(), + params.get("id").unwrap() + ) + }, + ), + ) + .route( + "/games/:id", + get( + |params: extract::Path>| async move { + format!( + "{}: games#show ({})", + params.get("version").unwrap(), + params.get("id").unwrap() + ) + }, + ), + ); - let app = route("/", get(|| async { "hi" })).nest("/:version/api", api_routes); + let app = Router::new() + .route("/", get(|| async { "hi" })) + .nest("/:version/api", api_routes); let addr = run_in_background(app).await; @@ -74,8 +77,8 @@ async fn nesting_apps() { #[tokio::test] async fn wrong_method_nest() { - let nested_app = route("/", get(|| async {})); - let app = crate::routing::nest("/", nested_app); + let nested_app = Router::new().route("/", get(|| async {})); + let app = Router::new().nest("/", nested_app); let addr = run_in_background(app).await; @@ -101,7 +104,7 @@ async fn wrong_method_nest() { #[tokio::test] async fn nesting_at_root() { - let app = nest("/", get(|uri: Uri| async move { uri.to_string() })); + let app = Router::new().nest("/", get(|uri: Uri| async move { uri.to_string() })); let addr = run_in_background(app).await; @@ -130,14 +133,16 @@ async fn nesting_at_root() { #[tokio::test] async fn nested_url_extractor() { - let app = nest( + let app = Router::new().nest( "/foo", - nest( + Router::new().nest( "/bar", - route("/baz", get(|uri: Uri| async move { uri.to_string() })).route( - "/qux", - get(|req: Request| async move { req.uri().to_string() }), - ), + Router::new() + .route("/baz", get(|uri: Uri| async move { uri.to_string() })) + .route( + "/qux", + get(|req: Request| async move { req.uri().to_string() }), + ), ), ); @@ -164,11 +169,11 @@ async fn nested_url_extractor() { #[tokio::test] async fn nested_url_original_extractor() { - let app = nest( + let app = Router::new().nest( "/foo", - nest( + Router::new().nest( "/bar", - route( + Router::new().route( "/baz", get(|uri: extract::OriginalUri| async move { uri.0.to_string() }), ), @@ -190,11 +195,11 @@ async fn nested_url_original_extractor() { #[tokio::test] async fn nested_service_sees_stripped_uri() { - let app = nest( + let app = Router::new().nest( "/foo", - nest( + Router::new().nest( "/bar", - route( + Router::new().route( "/baz", service_fn(|req: Request| async move { let body = box_body(Body::from(req.uri().to_string())); @@ -219,7 +224,7 @@ async fn nested_service_sees_stripped_uri() { #[tokio::test] async fn nest_static_file_server() { - let app = nest( + let app = Router::new().nest( "/static", service::get(tower_http::services::ServeDir::new(".")).handle_error(|error| { Ok::<_, Infallible>(( diff --git a/src/tests/or.rs b/src/tests/or.rs index e7b44f22..e9b55a15 100644 --- a/src/tests/or.rs +++ b/src/tests/or.rs @@ -7,8 +7,10 @@ use super::*; #[tokio::test] async fn basic() { - let one = route("/foo", get(|| async {})).route("/bar", get(|| async {})); - let two = route("/baz", get(|| async {})); + let one = Router::new() + .route("/foo", get(|| async {})) + .route("/bar", get(|| async {})); + let two = Router::new().route("/baz", get(|| async {})); let app = one.or(two); let addr = run_in_background(app).await; @@ -46,10 +48,10 @@ async fn basic() { #[tokio::test] async fn multiple_ors_balanced_differently() { - let one = route("/one", get(|| async { "one" })); - let two = route("/two", get(|| async { "two" })); - let three = route("/three", get(|| async { "three" })); - let four = route("/four", get(|| async { "four" })); + let one = Router::new().route("/one", get(|| async { "one" })); + let two = Router::new().route("/two", get(|| async { "two" })); + let three = Router::new().route("/three", get(|| async { "three" })); + let four = Router::new().route("/four", get(|| async { "four" })); test( "one", @@ -105,8 +107,10 @@ async fn multiple_ors_balanced_differently() { #[tokio::test] async fn or_nested_inside_other_thing() { - let inner = route("/bar", get(|| async {})).or(route("/baz", get(|| async {}))); - let app = nest("/foo", inner); + let inner = Router::new() + .route("/bar", get(|| async {})) + .or(Router::new().route("/baz", get(|| async {}))); + let app = Router::new().nest("/foo", inner); let addr = run_in_background(app).await; @@ -129,8 +133,8 @@ async fn or_nested_inside_other_thing() { #[tokio::test] async fn or_with_route_following() { - let one = route("/one", get(|| async { "one" })); - let two = route("/two", get(|| async { "two" })); + let one = Router::new().route("/one", get(|| async { "one" })); + let two = Router::new().route("/two", get(|| async { "two" })); let app = one.or(two).route("/three", get(|| async { "three" })); let addr = run_in_background(app).await; @@ -161,8 +165,10 @@ async fn or_with_route_following() { #[tokio::test] async fn layer() { - let one = route("/foo", get(|| async {})); - let two = route("/bar", get(|| async {})).layer(ConcurrencyLimitLayer::new(10)); + let one = Router::new().route("/foo", get(|| async {})); + let two = Router::new() + .route("/bar", get(|| async {})) + .layer(ConcurrencyLimitLayer::new(10)); let app = one.or(two); let addr = run_in_background(app).await; @@ -186,8 +192,9 @@ async fn layer() { #[tokio::test] async fn layer_and_handle_error() { - let one = route("/foo", get(|| async {})); - let two = route("/time-out", get(futures::future::pending::<()>)) + let one = Router::new().route("/foo", get(|| async {})); + let two = Router::new() + .route("/time-out", get(futures::future::pending::<()>)) .layer(TimeoutLayer::new(Duration::from_millis(10))) .handle_error(|_| Ok(StatusCode::REQUEST_TIMEOUT)); let app = one.or(two); @@ -206,8 +213,8 @@ async fn layer_and_handle_error() { #[tokio::test] async fn nesting() { - let one = route("/foo", get(|| async {})); - let two = nest("/bar", route("/baz", get(|| async {}))); + let one = Router::new().route("/foo", get(|| async {})); + let two = Router::new().nest("/bar", Router::new().route("/baz", get(|| async {}))); let app = one.or(two); let addr = run_in_background(app).await; @@ -224,8 +231,8 @@ async fn nesting() { #[tokio::test] async fn boxed() { - let one = route("/foo", get(|| async {})).boxed(); - let two = route("/bar", get(|| async {})).boxed(); + let one = Router::new().route("/foo", get(|| async {})).boxed(); + let two = Router::new().route("/bar", get(|| async {})).boxed(); let app = one.or(two); let addr = run_in_background(app).await; @@ -242,13 +249,14 @@ async fn boxed() { #[tokio::test] async fn many_ors() { - let app = route("/r1", get(|| async {})) - .or(route("/r2", get(|| async {}))) - .or(route("/r3", get(|| async {}))) - .or(route("/r4", get(|| async {}))) - .or(route("/r5", get(|| async {}))) - .or(route("/r6", get(|| async {}))) - .or(route("/r7", get(|| async {}))); + let app = Router::new() + .route("/r1", get(|| async {})) + .or(Router::new().route("/r2", get(|| async {}))) + .or(Router::new().route("/r3", get(|| async {}))) + .or(Router::new().route("/r4", get(|| async {}))) + .or(Router::new().route("/r5", get(|| async {}))) + .or(Router::new().route("/r6", get(|| async {}))) + .or(Router::new().route("/r7", get(|| async {}))); let addr = run_in_background(app).await; @@ -273,18 +281,19 @@ async fn many_ors() { #[tokio::test] async fn services() { - let app = route( - "/foo", - crate::service::get(service_fn(|_: Request| async { - Ok::<_, Infallible>(Response::new(Body::empty())) - })), - ) - .or(route( - "/bar", - crate::service::get(service_fn(|_: Request| async { - Ok::<_, Infallible>(Response::new(Body::empty())) - })), - )); + let app = Router::new() + .route( + "/foo", + crate::service::get(service_fn(|_: Request| async { + Ok::<_, Infallible>(Response::new(Body::empty())) + })), + ) + .or(Router::new().route( + "/bar", + crate::service::get(service_fn(|_: Request| async { + Ok::<_, Infallible>(Response::new(Body::empty())) + })), + )); let addr = run_in_background(app).await; @@ -319,8 +328,8 @@ async fn all_the_uris( #[tokio::test] async fn nesting_and_seeing_the_right_uri() { - let one = nest("/foo", route("/bar", get(all_the_uris))); - let two = route("/foo", 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 addr = run_in_background(one.or(two)).await; @@ -359,8 +368,11 @@ async fn nesting_and_seeing_the_right_uri() { #[tokio::test] async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() { - let one = nest("/foo", nest("/bar", route("/baz", get(all_the_uris)))); - let two = route("/foo", get(all_the_uris)); + let one = Router::new().nest( + "/foo", + Router::new().nest("/bar", Router::new().route("/baz", get(all_the_uris))), + ); + let two = Router::new().route("/foo", get(all_the_uris)); let addr = run_in_background(one.or(two)).await; @@ -399,9 +411,12 @@ async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() { #[tokio::test] async fn nesting_and_seeing_the_right_uri_ors_with_nesting() { - let one = nest("/foo", nest("/bar", route("/baz", get(all_the_uris)))); - let two = nest("/foo", route("/qux", get(all_the_uris))); - let three = route("/foo", get(all_the_uris)); + let one = Router::new().nest( + "/foo", + Router::new().nest("/bar", Router::new().route("/baz", get(all_the_uris))), + ); + let two = Router::new().nest("/foo", Router::new().route("/qux", get(all_the_uris))); + let three = Router::new().route("/foo", get(all_the_uris)); let addr = run_in_background(one.or(two).or(three)).await; @@ -455,8 +470,11 @@ async fn nesting_and_seeing_the_right_uri_ors_with_nesting() { #[tokio::test] async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() { - let one = nest("/foo", nest("/bar", route("/baz", get(all_the_uris)))); - let two = route("/foo/bar", get(all_the_uris)); + let one = Router::new().nest( + "/foo", + Router::new().nest("/bar", Router::new().route("/baz", get(all_the_uris))), + ); + let two = Router::new().route("/foo/bar", get(all_the_uris)); let addr = run_in_background(one.or(two)).await;