diff --git a/CHANGELOG.md b/CHANGELOG.md
index f62dd2d5..ff8a18bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -56,7 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
```rust,no_run
use axum::{
- handler::get,
+ routing::get,
http::StatusCode,
error_handling::HandleErrorLayer,
response::IntoResponse,
@@ -89,7 +89,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
use axum::{
Router, service,
body::Body,
- handler::get,
+ routing::service_method_router::get,
response::IntoResponse,
http::{Request, Response},
error_handling::HandleErrorExt, // for `.handle_error`
@@ -100,7 +100,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
let app = Router::new()
.route(
"/",
- service::get(service_fn(|_req: Request
| async {
+ get(service_fn(|_req: Request| async {
let contents = tokio::fs::read_to_string("some_file").await?;
Ok::<_, io::Error>(Response::new(Body::from(contents)))
}))
@@ -111,6 +111,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
// ...
}
```
+- **breaking:** Method routing for handlers have been moved from `axum::handler`
+ to `axum::routing`. So `axum::handler::get` now lives at `axum::routing::get`
+ ([#405])
+- **breaking:** Method routing for services have been moved from `axum::service`
+ to `axum::routing`. So `axum::service::get` now lives at
+ `axum::service_method_router::get` ([#405])
[#339]: https://github.com/tokio-rs/axum/pull/339
[#286]: https://github.com/tokio-rs/axum/pull/286
@@ -120,6 +126,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#396]: https://github.com/tokio-rs/axum/pull/396
[#402]: https://github.com/tokio-rs/axum/pull/402
[#404]: https://github.com/tokio-rs/axum/pull/404
+[#405]: https://github.com/tokio-rs/axum/pull/405
# 0.2.8 (07. October, 2021)
diff --git a/examples/async-graphql/src/main.rs b/examples/async-graphql/src/main.rs
index e06b9438..d6d9aa8c 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, AddExtensionLayer, Json, Router};
+use axum::{extract::Extension, response::Html, routing::get, AddExtensionLayer, Json, Router};
use starwars::{QueryRoot, StarWars, StarWarsSchema};
async fn graphql_handler(schema: Extension, req: Json) -> Json {
diff --git a/examples/chat/src/main.rs b/examples/chat/src/main.rs
index 0e35137f..68f0d7f2 100644
--- a/examples/chat/src/main.rs
+++ b/examples/chat/src/main.rs
@@ -11,8 +11,8 @@ use axum::{
ws::{Message, WebSocket, WebSocketUpgrade},
Extension,
},
- handler::get,
response::{Html, IntoResponse},
+ routing::get,
AddExtensionLayer, Router,
};
use futures::{sink::SinkExt, stream::StreamExt};
diff --git a/examples/customize-extractor-error/src/main.rs b/examples/customize-extractor-error/src/main.rs
index d7222e00..4b682faf 100644
--- a/examples/customize-extractor-error/src/main.rs
+++ b/examples/customize-extractor-error/src/main.rs
@@ -8,8 +8,8 @@ use axum::{
async_trait,
extract::rejection::JsonRejection,
extract::{FromRequest, RequestParts},
- handler::post,
http::StatusCode,
+ routing::post,
BoxError, Router,
};
use serde::{de::DeserializeOwned, Deserialize};
diff --git a/examples/error-handling-and-dependency-injection/src/main.rs b/examples/error-handling-and-dependency-injection/src/main.rs
index 4654564b..c55e385d 100644
--- a/examples/error-handling-and-dependency-injection/src/main.rs
+++ b/examples/error-handling-and-dependency-injection/src/main.rs
@@ -11,9 +11,9 @@ use axum::{
async_trait,
body::{Bytes, Full},
extract::{Extension, Path},
- handler::{get, post},
http::{Response, StatusCode},
response::IntoResponse,
+ routing::{get, post},
AddExtensionLayer, Json, Router,
};
use serde::{Deserialize, Serialize};
diff --git a/examples/form/src/main.rs b/examples/form/src/main.rs
index 42b9643d..4061e52c 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, Router};
+use axum::{extract::Form, response::Html, routing::get, Router};
use serde::Deserialize;
use std::net::SocketAddr;
diff --git a/examples/global-404-handler/src/main.rs b/examples/global-404-handler/src/main.rs
index f7464718..ca7e34d1 100644
--- a/examples/global-404-handler/src/main.rs
+++ b/examples/global-404-handler/src/main.rs
@@ -5,9 +5,10 @@
//! ```
use axum::{
- handler::{get, Handler},
+ handler::Handler,
http::StatusCode,
response::{Html, IntoResponse},
+ routing::get,
Router,
};
use std::net::SocketAddr;
diff --git a/examples/graceful_shutdown/src/main.rs b/examples/graceful_shutdown/src/main.rs
index efdb7a15..dd20f19c 100644
--- a/examples/graceful_shutdown/src/main.rs
+++ b/examples/graceful_shutdown/src/main.rs
@@ -5,7 +5,7 @@
//! kill or ctrl-c
//! ```
-use axum::{handler::get, response::Html, Router};
+use axum::{response::Html, routing::get, Router};
use std::net::SocketAddr;
#[tokio::main]
diff --git a/examples/hello-world/src/main.rs b/examples/hello-world/src/main.rs
index de069fa1..466caceb 100644
--- a/examples/hello-world/src/main.rs
+++ b/examples/hello-world/src/main.rs
@@ -4,7 +4,7 @@
//! cargo run -p example-hello-world
//! ```
-use axum::{handler::get, response::Html, Router};
+use axum::{response::Html, routing::get, Router};
use std::net::SocketAddr;
#[tokio::main]
diff --git a/examples/jwt/src/main.rs b/examples/jwt/src/main.rs
index e6bfee29..1a6e7681 100644
--- a/examples/jwt/src/main.rs
+++ b/examples/jwt/src/main.rs
@@ -10,9 +10,9 @@ use axum::{
async_trait,
body::{Bytes, Full},
extract::{FromRequest, RequestParts, TypedHeader},
- handler::{get, post},
http::{Response, StatusCode},
response::IntoResponse,
+ routing::{get, post},
Json, Router,
};
use headers::{authorization::Bearer, Authorization};
diff --git a/examples/key-value-store/src/main.rs b/examples/key-value-store/src/main.rs
index c0ddba48..5745dd87 100644
--- a/examples/key-value-store/src/main.rs
+++ b/examples/key-value-store/src/main.rs
@@ -10,9 +10,10 @@ use axum::{
body::Bytes,
error_handling::HandleErrorLayer,
extract::{ContentLengthLimit, Extension, Path},
- handler::{delete, get, Handler},
+ handler::Handler,
http::StatusCode,
response::IntoResponse,
+ routing::{delete, get},
Router,
};
use std::{
diff --git a/examples/low-level-rustls/src/main.rs b/examples/low-level-rustls/src/main.rs
index b82e6d56..60bda1d6 100644
--- a/examples/low-level-rustls/src/main.rs
+++ b/examples/low-level-rustls/src/main.rs
@@ -4,7 +4,7 @@
//! cargo run -p example-low-level-rustls
//! ```
-use axum::{handler::get, Router};
+use axum::{routing::get, Router};
use hyper::server::conn::Http;
use std::{fs::File, io::BufReader, sync::Arc};
use tokio::net::TcpListener;
diff --git a/examples/multipart-form/src/main.rs b/examples/multipart-form/src/main.rs
index 9c60ee3a..b734e65a 100644
--- a/examples/multipart-form/src/main.rs
+++ b/examples/multipart-form/src/main.rs
@@ -6,8 +6,8 @@
use axum::{
extract::{ContentLengthLimit, Multipart},
- handler::get,
response::Html,
+ routing::get,
Router,
};
use std::net::SocketAddr;
diff --git a/examples/oauth/src/main.rs b/examples/oauth/src/main.rs
index 90ae2f14..51da6053 100644
--- a/examples/oauth/src/main.rs
+++ b/examples/oauth/src/main.rs
@@ -11,9 +11,9 @@ use axum::{
async_trait,
body::{Bytes, Empty},
extract::{Extension, FromRequest, Query, RequestParts, TypedHeader},
- handler::get,
http::{header::SET_COOKIE, HeaderMap, Response},
response::{IntoResponse, Redirect},
+ routing::get,
AddExtensionLayer, Router,
};
use oauth2::{
diff --git a/examples/print-request-response/src/main.rs b/examples/print-request-response/src/main.rs
index 023e3c69..6c66eebf 100644
--- a/examples/print-request-response/src/main.rs
+++ b/examples/print-request-response/src/main.rs
@@ -7,8 +7,8 @@
use axum::{
body::{Body, BoxBody, Bytes},
error_handling::HandleErrorLayer,
- handler::post,
http::{Request, Response, StatusCode},
+ routing::post,
Router,
};
use std::net::SocketAddr;
diff --git a/examples/reverse-proxy/src/main.rs b/examples/reverse-proxy/src/main.rs
index 5ea93744..aefe1118 100644
--- a/examples/reverse-proxy/src/main.rs
+++ b/examples/reverse-proxy/src/main.rs
@@ -9,8 +9,8 @@
use axum::{
extract::Extension,
- handler::get,
http::{uri::Uri, Request, Response},
+ routing::get,
AddExtensionLayer, Router,
};
use hyper::{client::HttpConnector, Body};
diff --git a/examples/sessions/src/main.rs b/examples/sessions/src/main.rs
index db4dcbda..f16e800d 100644
--- a/examples/sessions/src/main.rs
+++ b/examples/sessions/src/main.rs
@@ -8,13 +8,13 @@ use async_session::{MemoryStore, Session, SessionStore as _};
use axum::{
async_trait,
extract::{Extension, FromRequest, RequestParts},
- handler::get,
http::{
self,
header::{HeaderMap, HeaderValue},
StatusCode,
},
response::IntoResponse,
+ routing::get,
AddExtensionLayer, Router,
};
use serde::{Deserialize, Serialize};
diff --git a/examples/sse/src/main.rs b/examples/sse/src/main.rs
index 406ad4c0..a9eb4129 100644
--- a/examples/sse/src/main.rs
+++ b/examples/sse/src/main.rs
@@ -7,9 +7,9 @@
use axum::{
error_handling::HandleErrorExt,
extract::TypedHeader,
- handler::get,
http::StatusCode,
response::sse::{Event, Sse},
+ routing::{get, service_method_router as service},
Router,
};
use futures::stream::{self, Stream};
@@ -25,15 +25,14 @@ async fn main() {
}
tracing_subscriber::fmt::init();
- let static_files_service = axum::service::get(
- ServeDir::new("examples/sse/assets").append_index_html_on_directories(true),
- )
- .handle_error(|error: std::io::Error| {
- (
- StatusCode::INTERNAL_SERVER_ERROR,
- format!("Unhandled internal error: {}", error),
- )
- });
+ let static_files_service =
+ service::get(ServeDir::new("examples/sse/assets").append_index_html_on_directories(true))
+ .handle_error(|error: std::io::Error| {
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ format!("Unhandled internal error: {}", error),
+ )
+ });
// build our application with a route
let app = Router::new()
diff --git a/examples/static-file-server/src/main.rs b/examples/static-file-server/src/main.rs
index ec449788..724b6e66 100644
--- a/examples/static-file-server/src/main.rs
+++ b/examples/static-file-server/src/main.rs
@@ -4,7 +4,10 @@
//! cargo run -p example-static-file-server
//! ```
-use axum::{error_handling::HandleErrorExt, http::StatusCode, service, Router};
+use axum::{
+ error_handling::HandleErrorExt, http::StatusCode, routing::service_method_router as service,
+ Router,
+};
use std::net::SocketAddr;
use tower_http::{services::ServeDir, trace::TraceLayer};
diff --git a/examples/templates/src/main.rs b/examples/templates/src/main.rs
index 685efa0d..a014722f 100644
--- a/examples/templates/src/main.rs
+++ b/examples/templates/src/main.rs
@@ -8,9 +8,9 @@ use askama::Template;
use axum::{
body::{Bytes, Full},
extract,
- handler::get,
http::{Response, StatusCode},
response::{Html, IntoResponse},
+ routing::get,
Router,
};
use std::{convert::Infallible, net::SocketAddr};
diff --git a/examples/testing/src/main.rs b/examples/testing/src/main.rs
index 54eddb58..02c459ce 100644
--- a/examples/testing/src/main.rs
+++ b/examples/testing/src/main.rs
@@ -5,7 +5,7 @@
//! ```
use axum::{
- handler::{get, post},
+ routing::{get, post},
Json, Router,
};
use tower_http::trace::TraceLayer;
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index 5e4ac543..719e78a2 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -16,9 +16,9 @@
use axum::{
error_handling::HandleErrorLayer,
extract::{Extension, Path, Query},
- handler::{get, patch},
http::StatusCode,
response::IntoResponse,
+ routing::{get, patch},
Json, Router,
};
use serde::{Deserialize, Serialize};
diff --git a/examples/tokio-postgres/src/main.rs b/examples/tokio-postgres/src/main.rs
index 6ea48030..f37de8bc 100644
--- a/examples/tokio-postgres/src/main.rs
+++ b/examples/tokio-postgres/src/main.rs
@@ -7,8 +7,8 @@
use axum::{
async_trait,
extract::{Extension, FromRequest, RequestParts},
- handler::get,
http::StatusCode,
+ routing::get,
AddExtensionLayer, Router,
};
use bb8::{Pool, PooledConnection};
diff --git a/examples/tracing-aka-logging/src/main.rs b/examples/tracing-aka-logging/src/main.rs
index b798b553..863e686d 100644
--- a/examples/tracing-aka-logging/src/main.rs
+++ b/examples/tracing-aka-logging/src/main.rs
@@ -6,9 +6,9 @@
use axum::{
body::Bytes,
- handler::get,
http::{HeaderMap, Request, Response},
response::Html,
+ routing::get,
Router,
};
use std::{net::SocketAddr, time::Duration};
diff --git a/examples/unix-domain-socket/src/main.rs b/examples/unix-domain-socket/src/main.rs
index a1ebff1d..ff224490 100644
--- a/examples/unix-domain-socket/src/main.rs
+++ b/examples/unix-domain-socket/src/main.rs
@@ -7,8 +7,8 @@
use axum::{
body::Body,
extract::connect_info::{self, ConnectInfo},
- handler::get,
http::{Method, Request, StatusCode, Uri},
+ routing::get,
Router,
};
use futures::ready;
diff --git a/examples/validator/src/main.rs b/examples/validator/src/main.rs
index e49e6dbd..a1ddebca 100644
--- a/examples/validator/src/main.rs
+++ b/examples/validator/src/main.rs
@@ -14,9 +14,9 @@ use async_trait::async_trait;
use axum::{
body::{Bytes, Full},
extract::{Form, FromRequest, RequestParts},
- handler::get,
http::{Response, StatusCode},
response::{Html, IntoResponse},
+ routing::get,
BoxError, Router,
};
use serde::{de::DeserializeOwned, Deserialize};
diff --git a/examples/versioning/src/main.rs b/examples/versioning/src/main.rs
index 3a78a299..399ba210 100644
--- a/examples/versioning/src/main.rs
+++ b/examples/versioning/src/main.rs
@@ -8,9 +8,9 @@ use axum::{
async_trait,
body::{Bytes, Full},
extract::{FromRequest, Path, RequestParts},
- handler::get,
http::{Response, StatusCode},
response::IntoResponse,
+ routing::get,
Router,
};
use std::collections::HashMap;
diff --git a/examples/websockets/src/main.rs b/examples/websockets/src/main.rs
index fbde0803..12fb6b6e 100644
--- a/examples/websockets/src/main.rs
+++ b/examples/websockets/src/main.rs
@@ -12,9 +12,9 @@ use axum::{
ws::{Message, WebSocket, WebSocketUpgrade},
TypedHeader,
},
- handler::get,
http::StatusCode,
response::IntoResponse,
+ routing::{get, service_method_router as service},
Router,
};
use std::net::SocketAddr;
@@ -35,7 +35,7 @@ async fn main() {
let app = Router::new()
.nest(
"/",
- axum::service::get(
+ service::get(
ServeDir::new("examples/websockets/assets").append_index_html_on_directories(true),
)
.handle_error(|error: std::io::Error| {
diff --git a/src/body/stream_body.rs b/src/body/stream_body.rs
index d60af154..b9e360d7 100644
--- a/src/body/stream_body.rs
+++ b/src/body/stream_body.rs
@@ -26,7 +26,7 @@ pin_project! {
/// ```
/// use axum::{
/// Router,
- /// handler::get,
+ /// routing::get,
/// body::StreamBody,
/// response::IntoResponse,
/// };
diff --git a/src/extract/connect_info.rs b/src/extract/connect_info.rs
index bcd97344..ba51a9cc 100644
--- a/src/extract/connect_info.rs
+++ b/src/extract/connect_info.rs
@@ -134,7 +134,7 @@ where
mod tests {
use super::*;
use crate::Server;
- use crate::{handler::get, Router};
+ use crate::{routing::get, Router};
use std::net::{SocketAddr, TcpListener};
#[tokio::test]
diff --git a/src/extract/content_length_limit.rs b/src/extract/content_length_limit.rs
index 3313ac03..fc8cb8f4 100644
--- a/src/extract/content_length_limit.rs
+++ b/src/extract/content_length_limit.rs
@@ -11,7 +11,7 @@ use std::ops::Deref;
/// ```rust,no_run
/// use axum::{
/// extract::ContentLengthLimit,
-/// handler::post,
+/// routing::post,
/// Router,
/// };
///
diff --git a/src/extract/extension.rs b/src/extract/extension.rs
index 7e6765d5..762af024 100644
--- a/src/extract/extension.rs
+++ b/src/extract/extension.rs
@@ -12,7 +12,7 @@ use std::ops::Deref;
/// use axum::{
/// AddExtensionLayer,
/// extract::Extension,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use std::sync::Arc;
diff --git a/src/extract/extractor_middleware.rs b/src/extract/extractor_middleware.rs
index 2bcb9ac4..f57472e2 100644
--- a/src/extract/extractor_middleware.rs
+++ b/src/extract/extractor_middleware.rs
@@ -38,7 +38,7 @@ use tower_service::Service;
/// ```rust
/// use axum::{
/// extract::{extractor_middleware, FromRequest, RequestParts},
-/// handler::{get, post},
+/// routing::{get, post},
/// Router,
/// };
/// use http::StatusCode;
diff --git a/src/extract/form.rs b/src/extract/form.rs
index 1edccb11..c4d017ca 100644
--- a/src/extract/form.rs
+++ b/src/extract/form.rs
@@ -16,7 +16,7 @@ use std::ops::Deref;
/// ```rust,no_run
/// use axum::{
/// extract::Form,
-/// handler::post,
+/// routing::post,
/// Router,
/// };
/// use serde::Deserialize;
diff --git a/src/extract/mod.rs b/src/extract/mod.rs
index 2a32291c..0ab95e09 100644
--- a/src/extract/mod.rs
+++ b/src/extract/mod.rs
@@ -10,7 +10,8 @@
//! ```rust,no_run
//! use axum::{
//! extract::Json,
-//! handler::{post, Handler},
+//! routing::post,
+//! handler::Handler,
//! Router,
//! };
//! use serde::Deserialize;
@@ -39,7 +40,7 @@
//! use axum::{
//! async_trait,
//! extract::{FromRequest, RequestParts},
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//! use http::{StatusCode, header::{HeaderValue, USER_AGENT}};
@@ -94,7 +95,7 @@
//! use axum::{
//! extract::{self, BodyStream},
//! body::Body,
-//! handler::get,
+//! routing::get,
//! http::{header::HeaderMap, Request},
//! Router,
//! };
diff --git a/src/extract/multipart.rs b/src/extract/multipart.rs
index b2b6b26f..fcfd0642 100644
--- a/src/extract/multipart.rs
+++ b/src/extract/multipart.rs
@@ -22,7 +22,7 @@ use std::{
/// ```rust,no_run
/// use axum::{
/// extract::Multipart,
-/// handler::post,
+/// routing::post,
/// Router,
/// };
/// use futures::stream::StreamExt;
diff --git a/src/extract/path/mod.rs b/src/extract/path/mod.rs
index a76a802d..2fcefd4c 100644
--- a/src/extract/path/mod.rs
+++ b/src/extract/path/mod.rs
@@ -24,7 +24,7 @@ use std::{
/// ```rust,no_run
/// use axum::{
/// extract::Path,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use uuid::Uuid;
@@ -46,7 +46,7 @@ use std::{
/// ```rust,no_run
/// use axum::{
/// extract::Path,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use uuid::Uuid;
@@ -68,7 +68,7 @@ use std::{
/// ```rust,no_run
/// use axum::{
/// extract::Path,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use serde::Deserialize;
@@ -97,7 +97,7 @@ use std::{
/// ```rust,no_run
/// use axum::{
/// extract::Path,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use std::collections::HashMap;
@@ -175,7 +175,7 @@ where
mod tests {
use super::*;
use crate::tests::*;
- use crate::{handler::get, Router};
+ use crate::{routing::get, Router};
use std::collections::HashMap;
#[tokio::test]
diff --git a/src/extract/query.rs b/src/extract/query.rs
index 975f9f85..7d08ced9 100644
--- a/src/extract/query.rs
+++ b/src/extract/query.rs
@@ -12,7 +12,7 @@ use std::ops::Deref;
/// ```rust,no_run
/// use axum::{
/// extract::Query,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use serde::Deserialize;
diff --git a/src/extract/raw_query.rs b/src/extract/raw_query.rs
index b802a675..f8d25393 100644
--- a/src/extract/raw_query.rs
+++ b/src/extract/raw_query.rs
@@ -9,7 +9,7 @@ use std::convert::Infallible;
/// ```rust,no_run
/// use axum::{
/// extract::RawQuery,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use futures::StreamExt;
diff --git a/src/extract/request_parts.rs b/src/extract/request_parts.rs
index 22c1c517..c76d39c8 100644
--- a/src/extract/request_parts.rs
+++ b/src/extract/request_parts.rs
@@ -94,7 +94,7 @@ where
///
/// ```
/// use axum::{
-/// handler::get,
+/// routing::get,
/// Router,
/// extract::OriginalUri,
/// http::Uri
@@ -181,7 +181,7 @@ where
/// ```rust,no_run
/// use axum::{
/// extract::BodyStream,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use futures::StreamExt;
@@ -252,7 +252,7 @@ fn body_stream_traits() {
/// ```rust,no_run
/// use axum::{
/// extract::RawBody,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use futures::StreamExt;
@@ -326,7 +326,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
- use crate::{body::Body, handler::post, tests::*, Router};
+ use crate::{body::Body, routing::post, tests::*, Router};
use http::StatusCode;
#[tokio::test]
diff --git a/src/extract/typed_header.rs b/src/extract/typed_header.rs
index b1f6945c..7b4abb73 100644
--- a/src/extract/typed_header.rs
+++ b/src/extract/typed_header.rs
@@ -13,7 +13,7 @@ use std::{convert::Infallible, ops::Deref};
/// ```rust,no_run
/// use axum::{
/// extract::TypedHeader,
-/// handler::get,
+/// routing::get,
/// Router,
/// };
/// use headers::UserAgent;
@@ -140,7 +140,7 @@ impl std::error::Error for TypedHeaderRejection {
#[cfg(test)]
mod tests {
use super::*;
- use crate::{handler::get, response::IntoResponse, tests::*, Router};
+ use crate::{response::IntoResponse, routing::get, tests::*, Router};
#[tokio::test]
async fn typed_header() {
diff --git a/src/extract/ws.rs b/src/extract/ws.rs
index 361b5dd5..4b76857c 100644
--- a/src/extract/ws.rs
+++ b/src/extract/ws.rs
@@ -5,7 +5,7 @@
//! ```
//! use axum::{
//! extract::ws::{WebSocketUpgrade, WebSocket},
-//! handler::get,
+//! routing::get,
//! response::IntoResponse,
//! Router,
//! };
@@ -96,7 +96,7 @@ use tokio_tungstenite::{
/// Extractor for establishing WebSocket connections.
///
/// Note: This extractor requires the request method to be `GET` so it should
-/// always be used with [`get`](crate::handler::get). Requests with other methods will be
+/// always be used with [`get`](crate::routing::get). Requests with other methods will be
/// rejected.
///
/// See the [module docs](self) for an example.
@@ -138,7 +138,7 @@ impl WebSocketUpgrade {
/// ```
/// use axum::{
/// extract::ws::{WebSocketUpgrade, WebSocket},
- /// handler::get,
+ /// routing::get,
/// response::IntoResponse,
/// Router,
/// };
diff --git a/src/handler/future.rs b/src/handler/future.rs
index 71dcbe3b..144110a4 100644
--- a/src/handler/future.rs
+++ b/src/handler/future.rs
@@ -1,69 +1,9 @@
//! Handler future types.
-use crate::body::{box_body, BoxBody};
-use crate::util::{Either, EitherProj};
-use futures_util::{
- future::{BoxFuture, Map},
- ready,
-};
-use http::{Method, Request, Response};
-use http_body::Empty;
-use pin_project_lite::pin_project;
-use std::{
- convert::Infallible,
- fmt,
- future::Future,
- pin::Pin,
- task::{Context, Poll},
-};
-use tower::util::Oneshot;
-use tower_service::Service;
-
-pin_project! {
- /// The response future for [`OnMethod`](super::OnMethod).
- pub struct OnMethodFuture
- where
- F: Service>
- {
- #[pin]
- pub(super) inner: Either<
- BoxFuture<'static, Response>,
- Oneshot>,
- >,
- pub(super) req_method: Method,
- }
-}
-
-impl Future for OnMethodFuture
-where
- F: Service, Response = Response>,
-{
- type Output = Result, F::Error>;
-
- fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
- let this = self.project();
- let response = match this.inner.project() {
- EitherProj::A { inner } => ready!(inner.poll(cx)),
- EitherProj::B { inner } => ready!(inner.poll(cx))?,
- };
-
- if this.req_method == &Method::HEAD {
- let response = response.map(|_| box_body(Empty::new()));
- Poll::Ready(Ok(response))
- } else {
- Poll::Ready(Ok(response))
- }
- }
-}
-
-impl fmt::Debug for OnMethodFuture
-where
- F: Service>,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("OnMethodFuture").finish()
- }
-}
+use crate::body::BoxBody;
+use futures_util::future::{BoxFuture, Map};
+use http::Response;
+use std::convert::Infallible;
opaque_future! {
/// The response future for [`IntoService`](super::IntoService).
diff --git a/src/handler/mod.rs b/src/handler/mod.rs
index c0d1598b..1116bc58 100644
--- a/src/handler/mod.rs
+++ b/src/handler/mod.rs
@@ -4,20 +4,13 @@ use crate::{
body::{box_body, BoxBody},
extract::{FromRequest, RequestParts},
response::IntoResponse,
- routing::{EmptyRouter, MethodFilter},
- util::Either,
+ routing::{EmptyRouter, MethodRouter},
BoxError,
};
use async_trait::async_trait;
use bytes::Bytes;
use http::{Request, Response};
-use std::{
- convert::Infallible,
- fmt,
- future::Future,
- marker::PhantomData,
- task::{Context, Poll},
-};
+use std::{fmt, future::Future, marker::PhantomData};
use tower::ServiceExt;
use tower_layer::Layer;
use tower_service::Service;
@@ -27,187 +20,6 @@ mod into_service;
pub use self::into_service::IntoService;
-/// Route requests with any standard HTTP method to the given handler.
-///
-/// # Example
-///
-/// ```rust
-/// use axum::{
-/// handler::any,
-/// Router,
-/// };
-///
-/// async fn handler() {}
-///
-/// let app = Router::new().route("/", any(handler));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
-/// ```
-///
-/// Note that this only accepts the standard HTTP methods. If you need to
-/// support non-standard methods use [`Handler::into_service`]:
-///
-/// ```rust
-/// use axum::{
-/// handler::Handler,
-/// Router,
-/// };
-///
-/// async fn handler() {}
-///
-/// let app = Router::new().route("/", handler.into_service());
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
-/// ```
-pub fn any(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::all(), handler)
-}
-
-/// Route `CONNECT` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn connect(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::CONNECT, handler)
-}
-
-/// Route `DELETE` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn delete(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::DELETE, handler)
-}
-
-/// Route `GET` requests to the given handler.
-///
-/// # Example
-///
-/// ```rust
-/// use axum::{
-/// handler::get,
-/// Router,
-/// };
-///
-/// async fn handler() {}
-///
-/// // Requests to `GET /` will go to `handler`.
-/// let app = Router::new().route("/", get(handler));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
-/// ```
-///
-/// Note that `get` routes will also be called for `HEAD` requests but will have
-/// the response body removed. Make sure to add explicit `HEAD` routes
-/// afterwards.
-pub fn get(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::GET | MethodFilter::HEAD, handler)
-}
-
-/// Route `HEAD` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn head(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::HEAD, handler)
-}
-
-/// Route `OPTIONS` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn options(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::OPTIONS, handler)
-}
-
-/// Route `PATCH` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn patch(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::PATCH, handler)
-}
-
-/// Route `POST` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn post(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::POST, handler)
-}
-
-/// Route `PUT` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn put(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::PUT, handler)
-}
-
-/// Route `TRACE` requests to the given handler.
-///
-/// See [`get`] for an example.
-pub fn trace(handler: H) -> OnMethod
-where
- H: Handler,
-{
- on(MethodFilter::TRACE, handler)
-}
-
-/// Route requests with the given method to the handler.
-///
-/// # Example
-///
-/// ```rust
-/// use axum::{
-/// handler::on,
-/// Router,
-/// routing::MethodFilter,
-/// };
-///
-/// async fn handler() {}
-///
-/// // Requests to `POST /` will go to `handler`.
-/// let app = Router::new().route("/", on(MethodFilter::POST, handler));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
-/// ```
-pub fn on(method: MethodFilter, handler: H) -> OnMethod
-where
- H: Handler,
-{
- OnMethod {
- method,
- handler,
- fallback: EmptyRouter::method_not_allowed(),
- _marker: PhantomData,
- }
-}
-
pub(crate) mod sealed {
#![allow(unreachable_pub, missing_docs, missing_debug_implementations)]
@@ -250,7 +62,8 @@ pub trait Handler: Clone + Send + Sized + 'static {
///
/// ```rust
/// use axum::{
- /// handler::{get, Handler},
+ /// routing::get,
+ /// handler::Handler,
/// Router,
/// };
/// use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit};
@@ -265,9 +78,9 @@ pub trait Handler: Clone + Send + Sized + 'static {
/// ```
fn layer(self, layer: L) -> Layered
where
- L: Layer>,
+ L: Layer>,
{
- Layered::new(layer.layer(any(self)))
+ Layered::new(layer.layer(crate::routing::any(self)))
}
/// Convert the handler into a [`Service`].
@@ -424,243 +237,9 @@ impl Layered {
}
}
-/// A handler [`Service`] that accepts requests based on a [`MethodFilter`] and
-/// allows chaining additional handlers.
-pub struct OnMethod {
- pub(crate) method: MethodFilter,
- pub(crate) handler: H,
- pub(crate) fallback: F,
- pub(crate) _marker: PhantomData (B, T)>,
-}
-
#[test]
fn traits() {
use crate::tests::*;
- assert_send::>();
- assert_sync::>();
-}
-
-impl fmt::Debug for OnMethod
-where
- T: fmt::Debug,
- F: fmt::Debug,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("OnMethod")
- .field("method", &self.method)
- .field("handler", &format_args!("{}", std::any::type_name::()))
- .field("fallback", &self.fallback)
- .finish()
- }
-}
-
-impl Clone for OnMethod
-where
- H: Clone,
- F: Clone,
-{
- fn clone(&self) -> Self {
- Self {
- method: self.method,
- handler: self.handler.clone(),
- fallback: self.fallback.clone(),
- _marker: PhantomData,
- }
- }
-}
-
-impl Copy for OnMethod
-where
- H: Copy,
- F: Copy,
-{
-}
-
-impl OnMethod {
- /// Chain an additional handler that will accept all requests regardless of
- /// its HTTP method.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn any(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::all(), handler)
- }
-
- /// Chain an additional handler that will only accept `CONNECT` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn connect(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::CONNECT, handler)
- }
-
- /// Chain an additional handler that will only accept `DELETE` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn delete(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::DELETE, handler)
- }
-
- /// Chain an additional handler that will only accept `GET` requests.
- ///
- /// # Example
- ///
- /// ```rust
- /// use axum::{handler::post, Router};
- ///
- /// async fn handler() {}
- ///
- /// async fn other_handler() {}
- ///
- /// // Requests to `GET /` will go to `handler` and `POST /` will go to
- /// // `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();
- /// # };
- /// ```
- ///
- /// Note that `get` routes will also be called for `HEAD` requests but will have
- /// the response body removed. Make sure to add explicit `HEAD` routes
- /// afterwards.
- pub fn get(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::GET | MethodFilter::HEAD, handler)
- }
-
- /// Chain an additional handler that will only accept `HEAD` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn head(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::HEAD, handler)
- }
-
- /// Chain an additional handler that will only accept `OPTIONS` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn options(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::OPTIONS, handler)
- }
-
- /// Chain an additional handler that will only accept `PATCH` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn patch(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::PATCH, handler)
- }
-
- /// Chain an additional handler that will only accept `POST` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn post(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::POST, handler)
- }
-
- /// Chain an additional handler that will only accept `PUT` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn put(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::PUT, handler)
- }
-
- /// Chain an additional handler that will only accept `TRACE` requests.
- ///
- /// See [`OnMethod::get`] for an example.
- pub fn trace(self, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- self.on(MethodFilter::TRACE, handler)
- }
-
- /// Chain an additional handler that will accept requests matching the given
- /// `MethodFilter`.
- ///
- /// # Example
- ///
- /// ```rust
- /// use axum::{
- /// handler::get,
- /// Router,
- /// routing::MethodFilter
- /// };
- ///
- /// async fn handler() {}
- ///
- /// async fn other_handler() {}
- ///
- /// // Requests to `GET /` will go to `handler` and `DELETE /` will go to
- /// // `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();
- /// # };
- /// ```
- pub fn on(self, method: MethodFilter, handler: H2) -> OnMethod
- where
- H2: Handler,
- {
- OnMethod {
- method,
- handler,
- fallback: self,
- _marker: PhantomData,
- }
- }
-}
-
-impl Service> for OnMethod
-where
- H: Handler,
- F: Service, Response = Response, Error = Infallible> + Clone,
- B: Send + 'static,
-{
- type Response = Response;
- type Error = Infallible;
- type Future = future::OnMethodFuture;
-
- fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> {
- Poll::Ready(Ok(()))
- }
-
- fn call(&mut self, req: Request) -> Self::Future {
- let req_method = req.method().clone();
-
- let fut = if self.method.matches(req.method()) {
- let fut = Handler::call(self.handler.clone(), req);
- Either::A { inner: fut }
- } else {
- let fut = self.fallback.clone().oneshot(req);
- Either::B { inner: fut }
- };
-
- future::OnMethodFuture {
- inner: fut,
- req_method,
- }
- }
+ assert_send::>();
+ assert_sync::>();
}
diff --git a/src/json.rs b/src/json.rs
index 11db3360..93f9963a 100644
--- a/src/json.rs
+++ b/src/json.rs
@@ -29,7 +29,7 @@ use std::{
/// ```rust,no_run
/// use axum::{
/// extract,
-/// handler::post,
+/// routing::post,
/// Router,
/// };
/// use serde::Deserialize;
@@ -58,7 +58,7 @@ use std::{
/// ```
/// use axum::{
/// extract::Path,
-/// handler::get,
+/// routing::get,
/// Router,
/// Json,
/// };
diff --git a/src/lib.rs b/src/lib.rs
index 19d84c98..0774ba17 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -55,7 +55,7 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//!
@@ -134,7 +134,7 @@
//! ::: axum/src/handler/mod.rs:116:8
//! |
//! 116 | H: Handler,
-//! | ------------- required by this bound in `axum::handler::get`
+//! | ------------- required by this bound in `axum::routing::get`
//! ```
//!
//! This error doesn't tell you _why_ your function doesn't implement
@@ -147,7 +147,7 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//!
@@ -186,8 +186,8 @@
//! ```rust,no_run
//! use axum::{
//! Router,
-//! service,
//! body::Body,
+//! routing::service_method_router as service,
//! error_handling::HandleErrorExt,
//! http::{Request, StatusCode},
//! };
@@ -248,8 +248,7 @@
//! ```compile_fail
//! use axum::{
//! Router,
-//! service,
-//! handler::get,
+//! routing::{get, service_method_router as service},
//! http::{Request, Response},
//! body::Body,
//! };
@@ -277,9 +276,9 @@
//!
//! ```
//! use axum::{
-//! Router, service,
+//! Router,
//! body::Body,
-//! handler::get,
+//! routing::{get, service_method_router as service},
//! response::IntoResponse,
//! http::{Request, Response},
//! error_handling::HandleErrorExt,
@@ -321,7 +320,7 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//!
@@ -337,7 +336,7 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::get,
+//! routing::get,
//! extract::Path,
//! Router,
//! };
@@ -358,7 +357,7 @@
//! use axum::{
//! body::{Body, BoxBody},
//! http::Request,
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//! use tower_http::services::ServeFile;
@@ -387,7 +386,7 @@
//! the prefix stripped.
//!
//! ```rust
-//! use axum::{handler::get, http::Uri, Router};
+//! use axum::{routing::get, http::Uri, Router};
//!
//! let app = Router::new()
//! .route("/foo/*rest", get(|uri: Uri| async {
@@ -412,7 +411,7 @@
//! ```rust,no_run
//! use axum::{
//! extract::Json,
-//! handler::post,
+//! routing::post,
//! Router,
//! };
//! use serde::Deserialize;
@@ -442,7 +441,7 @@
//! ```rust,no_run
//! use axum::{
//! extract::{Json, TypedHeader, Path, Extension, Query},
-//! handler::post,
+//! routing::post,
//! http::{Request, header::HeaderMap},
//! body::{Bytes, Body},
//! Router,
@@ -506,7 +505,7 @@
//! ```rust,no_run
//! use axum::{
//! extract,
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//! use uuid::Uuid;
@@ -550,7 +549,7 @@
//! ```rust,no_run
//! use axum::{
//! extract::TypedHeader,
-//! handler::get,
+//! routing::get,
//! http::header::HeaderMap,
//! Router,
//! };
@@ -574,7 +573,7 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::get,
+//! routing::get,
//! http::Request,
//! body::Body,
//! Router,
@@ -601,7 +600,7 @@
//! ```rust,no_run
//! use axum::{
//! extract::Json,
-//! handler::post,
+//! routing::post,
//! Router,
//! };
//! use serde_json::Value;
@@ -626,7 +625,7 @@
//! ```rust,no_run
//! use axum::{
//! extract::{Json, rejection::JsonRejection},
-//! handler::post,
+//! routing::post,
//! Router,
//! };
//! use serde_json::Value;
@@ -680,7 +679,8 @@
//! ```rust,no_run
//! use axum::{
//! body::Body,
-//! handler::{get, Handler},
+//! routing::get,
+//! handler::Handler,
//! http::{Request, header::{HeaderMap, HeaderName, HeaderValue}},
//! response::{IntoResponse, Html, Json, Headers},
//! Router,
@@ -819,7 +819,8 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::{get, Handler},
+//! handler::Handler,
+//! routing::get,
//! Router,
//! };
//! use tower::limit::ConcurrencyLimitLayer;
@@ -842,7 +843,7 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::{get, post},
+//! routing::{get, post},
//! Router,
//! };
//! use tower::limit::ConcurrencyLimitLayer;
@@ -865,7 +866,7 @@
//!
//! ```rust,no_run
//! use axum::{
-//! handler::{get, post},
+//! routing::{get, post},
//! Router,
//! };
//! use tower::limit::ConcurrencyLimitLayer;
@@ -895,7 +896,7 @@
//! ```rust,no_run
//! use axum::{
//! body::Body,
-//! handler::get,
+//! routing::get,
//! http::{Request, StatusCode},
//! error_handling::HandleErrorLayer,
//! response::IntoResponse,
@@ -945,7 +946,7 @@
//! ```rust,no_run
//! use axum::{
//! body::{Body, BoxBody},
-//! handler::get,
+//! routing::get,
//! http::{Request, Response},
//! error_handling::HandleErrorLayer,
//! Router,
@@ -1004,7 +1005,7 @@
//! ```
//! use axum::{
//! body::{Body, BoxBody},
-//! handler::get,
+//! routing::get,
//! http::{Request, Response},
//! Router,
//! };
@@ -1069,7 +1070,7 @@
//! use axum::{
//! AddExtensionLayer,
//! extract,
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//! use std::sync::Arc;
@@ -1220,7 +1221,6 @@ pub mod extract;
pub mod handler;
pub mod response;
pub mod routing;
-pub mod service;
#[cfg(test)]
mod tests;
diff --git a/src/response/headers.rs b/src/response/headers.rs
index 03e24a85..2b086e1f 100644
--- a/src/response/headers.rs
+++ b/src/response/headers.rs
@@ -18,7 +18,7 @@ use tower::util::Either;
/// use axum::{
/// Router,
/// response::{IntoResponse, Headers},
-/// handler::get,
+/// routing::get,
/// };
/// use http::header::{HeaderName, HeaderValue};
///
diff --git a/src/response/mod.rs b/src/response/mod.rs
index 41e5299b..94d39054 100644
--- a/src/response/mod.rs
+++ b/src/response/mod.rs
@@ -40,7 +40,7 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse};
/// use axum::{
/// Router,
/// body::Body,
-/// handler::get,
+/// routing::get,
/// http::{Response, StatusCode},
/// response::IntoResponse,
/// };
@@ -87,7 +87,7 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse};
///
/// ```rust
/// use axum::{
-/// handler::get,
+/// routing::get,
/// response::IntoResponse,
/// Router,
/// };
diff --git a/src/response/redirect.rs b/src/response/redirect.rs
index 088d6151..91df811c 100644
--- a/src/response/redirect.rs
+++ b/src/response/redirect.rs
@@ -10,7 +10,7 @@ use std::convert::TryFrom;
///
/// ```rust
/// use axum::{
-/// handler::get,
+/// routing::get,
/// response::Redirect,
/// Router,
/// };
diff --git a/src/response/sse.rs b/src/response/sse.rs
index 3d8e5dff..b6108cf4 100644
--- a/src/response/sse.rs
+++ b/src/response/sse.rs
@@ -5,7 +5,7 @@
//! ```
//! use axum::{
//! Router,
-//! handler::get,
+//! routing::get,
//! response::sse::{Event, KeepAlive, Sse},
//! };
//! use std::{time::Duration, convert::Infallible};
diff --git a/src/routing/handler_method_router.rs b/src/routing/handler_method_router.rs
new file mode 100644
index 00000000..6ae950e1
--- /dev/null
+++ b/src/routing/handler_method_router.rs
@@ -0,0 +1,485 @@
+//! Routing for handlers based on HTTP methods.
+
+use crate::{
+ body::{box_body, BoxBody},
+ handler::Handler,
+ routing::{EmptyRouter, MethodFilter},
+ util::{Either, EitherProj},
+};
+use futures_util::{future::BoxFuture, ready};
+use http::Method;
+use http::{Request, Response};
+use http_body::Empty;
+use pin_project_lite::pin_project;
+use std::{
+ convert::Infallible,
+ fmt,
+ future::Future,
+ marker::PhantomData,
+ pin::Pin,
+ task::{Context, Poll},
+};
+use tower::util::Oneshot;
+use tower::ServiceExt;
+use tower_service::Service;
+
+/// Route requests with any standard HTTP method to the given handler.
+///
+/// # Example
+///
+/// ```rust
+/// use axum::{
+/// routing::any,
+/// Router,
+/// };
+///
+/// async fn handler() {}
+///
+/// let app = Router::new().route("/", any(handler));
+/// # async {
+/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
+/// # };
+/// ```
+///
+/// Note that this only accepts the standard HTTP methods. If you need to
+/// support non-standard methods use [`Handler::into_service`]:
+///
+/// ```rust
+/// use axum::{
+/// handler::Handler,
+/// Router,
+/// };
+///
+/// async fn handler() {}
+///
+/// let app = Router::new().route("/", handler.into_service());
+/// # async {
+/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
+/// # };
+/// ```
+pub fn any(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::all(), handler)
+}
+
+/// Route `CONNECT` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn connect(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::CONNECT, handler)
+}
+
+/// Route `DELETE` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn delete(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::DELETE, handler)
+}
+
+/// Route `GET` requests to the given handler.
+///
+/// # Example
+///
+/// ```rust
+/// use axum::{
+/// routing::get,
+/// Router,
+/// };
+///
+/// async fn handler() {}
+///
+/// // Requests to `GET /` will go to `handler`.
+/// let app = Router::new().route("/", get(handler));
+/// # async {
+/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
+/// # };
+/// ```
+///
+/// Note that `get` routes will also be called for `HEAD` requests but will have
+/// the response body removed. Make sure to add explicit `HEAD` routes
+/// afterwards.
+pub fn get(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::GET | MethodFilter::HEAD, handler)
+}
+
+/// Route `HEAD` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn head(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::HEAD, handler)
+}
+
+/// Route `OPTIONS` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn options(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::OPTIONS, handler)
+}
+
+/// Route `PATCH` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn patch(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::PATCH, handler)
+}
+
+/// Route `POST` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn post(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::POST, handler)
+}
+
+/// Route `PUT` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn put(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::PUT, handler)
+}
+
+/// Route `TRACE` requests to the given handler.
+///
+/// See [`get`] for an example.
+pub fn trace(handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ on(MethodFilter::TRACE, handler)
+}
+
+/// Route requests with the given method to the handler.
+///
+/// # Example
+///
+/// ```rust
+/// use axum::{
+/// routing::on,
+/// Router,
+/// routing::MethodFilter,
+/// };
+///
+/// async fn handler() {}
+///
+/// // Requests to `POST /` will go to `handler`.
+/// let app = Router::new().route("/", on(MethodFilter::POST, handler));
+/// # async {
+/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
+/// # };
+/// ```
+pub fn on(method: MethodFilter, handler: H) -> MethodRouter
+where
+ H: Handler,
+{
+ MethodRouter {
+ method,
+ handler,
+ fallback: EmptyRouter::method_not_allowed(),
+ _marker: PhantomData,
+ }
+}
+
+/// A handler [`Service`] that accepts requests based on a [`MethodFilter`] and
+/// allows chaining additional handlers.
+pub struct MethodRouter {
+ pub(crate) method: MethodFilter,
+ pub(crate) handler: H,
+ pub(crate) fallback: F,
+ pub(crate) _marker: PhantomData (B, T)>,
+}
+
+impl fmt::Debug for MethodRouter
+where
+ T: fmt::Debug,
+ F: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MethodRouter")
+ .field("method", &self.method)
+ .field("handler", &format_args!("{}", std::any::type_name::()))
+ .field("fallback", &self.fallback)
+ .finish()
+ }
+}
+
+impl Clone for MethodRouter
+where
+ H: Clone,
+ F: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ method: self.method,
+ handler: self.handler.clone(),
+ fallback: self.fallback.clone(),
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl Copy for MethodRouter
+where
+ H: Copy,
+ F: Copy,
+{
+}
+
+impl MethodRouter {
+ /// Chain an additional handler that will accept all requests regardless of
+ /// its HTTP method.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn any(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::all(), handler)
+ }
+
+ /// Chain an additional handler that will only accept `CONNECT` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn connect(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::CONNECT, handler)
+ }
+
+ /// Chain an additional handler that will only accept `DELETE` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn delete(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::DELETE, handler)
+ }
+
+ /// Chain an additional handler that will only accept `GET` requests.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use axum::{routing::post, Router};
+ ///
+ /// async fn handler() {}
+ ///
+ /// async fn other_handler() {}
+ ///
+ /// // Requests to `GET /` will go to `handler` and `POST /` will go to
+ /// // `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();
+ /// # };
+ /// ```
+ ///
+ /// Note that `get` routes will also be called for `HEAD` requests but will have
+ /// the response body removed. Make sure to add explicit `HEAD` routes
+ /// afterwards.
+ pub fn get(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::GET | MethodFilter::HEAD, handler)
+ }
+
+ /// Chain an additional handler that will only accept `HEAD` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn head(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::HEAD, handler)
+ }
+
+ /// Chain an additional handler that will only accept `OPTIONS` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn options(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::OPTIONS, handler)
+ }
+
+ /// Chain an additional handler that will only accept `PATCH` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn patch(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::PATCH, handler)
+ }
+
+ /// Chain an additional handler that will only accept `POST` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn post(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::POST, handler)
+ }
+
+ /// Chain an additional handler that will only accept `PUT` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn put(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::PUT, handler)
+ }
+
+ /// Chain an additional handler that will only accept `TRACE` requests.
+ ///
+ /// See [`MethodRouter::get`] for an example.
+ pub fn trace(self, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ self.on(MethodFilter::TRACE, handler)
+ }
+
+ /// Chain an additional handler that will accept requests matching the given
+ /// `MethodFilter`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use axum::{
+ /// routing::get,
+ /// Router,
+ /// routing::MethodFilter
+ /// };
+ ///
+ /// async fn handler() {}
+ ///
+ /// async fn other_handler() {}
+ ///
+ /// // Requests to `GET /` will go to `handler` and `DELETE /` will go to
+ /// // `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();
+ /// # };
+ /// ```
+ pub fn on(self, method: MethodFilter, handler: H2) -> MethodRouter
+ where
+ H2: Handler,
+ {
+ MethodRouter {
+ method,
+ handler,
+ fallback: self,
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl Service> for MethodRouter
+where
+ H: Handler,
+ F: Service, Response = Response, Error = Infallible> + Clone,
+ B: Send + 'static,
+{
+ type Response = Response;
+ type Error = Infallible;
+ type Future = MethodRouterFuture;
+
+ fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn call(&mut self, req: Request) -> Self::Future {
+ let req_method = req.method().clone();
+
+ let fut = if self.method.matches(req.method()) {
+ let fut = Handler::call(self.handler.clone(), req);
+ Either::A { inner: fut }
+ } else {
+ let fut = self.fallback.clone().oneshot(req);
+ Either::B { inner: fut }
+ };
+
+ MethodRouterFuture {
+ inner: fut,
+ req_method,
+ }
+ }
+}
+
+pin_project! {
+ /// The response future for [`MethodRouter`].
+ pub struct MethodRouterFuture
+ where
+ F: Service>
+ {
+ #[pin]
+ pub(super) inner: Either<
+ BoxFuture<'static, Response>,
+ Oneshot>,
+ >,
+ pub(super) req_method: Method,
+ }
+}
+
+impl Future for MethodRouterFuture
+where
+ F: Service, Response = Response>,
+{
+ type Output = Result, F::Error>;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
+ let this = self.project();
+ let response = match this.inner.project() {
+ EitherProj::A { inner } => ready!(inner.poll(cx)),
+ EitherProj::B { inner } => ready!(inner.poll(cx))?,
+ };
+
+ if this.req_method == &Method::HEAD {
+ let response = response.map(|_| box_body(Empty::new()));
+ Poll::Ready(Ok(response))
+ } else {
+ Poll::Ready(Ok(response))
+ }
+ }
+}
+
+impl fmt::Debug for MethodRouterFuture
+where
+ F: Service>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MethodRouterFuture").finish()
+ }
+}
diff --git a/src/routing/mod.rs b/src/routing/mod.rs
index c489b234..59bbef70 100644
--- a/src/routing/mod.rs
+++ b/src/routing/mod.rs
@@ -1,4 +1,4 @@
-//! Routing between [`Service`]s.
+//! Routing between [`Service`]s and handlers.
use self::future::{EmptyRouterFuture, NestedFuture, RouteFuture, RoutesFuture};
use crate::{
@@ -28,12 +28,19 @@ use tower_layer::Layer;
use tower_service::Service;
pub mod future;
+pub mod handler_method_router;
+pub mod service_method_router;
mod method_filter;
mod or;
pub use self::method_filter::MethodFilter;
+#[doc(no_inline)]
+pub use self::handler_method_router::{
+ any, connect, delete, get, head, on, options, patch, post, put, trace, MethodRouter,
+};
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct RouteId(u64);
@@ -109,7 +116,7 @@ where
/// # Example
///
/// ```rust
- /// use axum::{handler::{get, delete}, Router};
+ /// use axum::{routing::{get, delete}, Router};
///
/// let app = Router::new()
/// .route("/", get(root))
@@ -136,7 +143,7 @@ where
/// Panics if the route overlaps with another route:
///
/// ```should_panic
- /// use axum::{handler::get, Router};
+ /// use axum::{routing::get, Router};
///
/// let app = Router::new()
/// .route("/", get(|| async {}))
@@ -149,7 +156,7 @@ where
/// This also applies to `nest` which is similar to a wildcard route:
///
/// ```should_panic
- /// use axum::{handler::get, Router};
+ /// use axum::{routing::get, Router};
///
/// let app = Router::new()
/// // this is similar to `/api/*`
@@ -164,7 +171,7 @@ where
/// Note that routes like `/:key` and `/foo` are considered overlapping:
///
/// ```should_panic
- /// use axum::{handler::get, Router};
+ /// use axum::{routing::get, Router};
///
/// let app = Router::new()
/// .route("/foo", get(|| async {}))
@@ -204,7 +211,7 @@ where
///
/// ```
/// use axum::{
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
/// use http::Uri;
@@ -239,7 +246,7 @@ where
/// ```
/// use axum::{
/// extract::Path,
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
/// use std::collections::HashMap;
@@ -265,7 +272,7 @@ where
/// ```
/// use axum::{
/// Router,
- /// service::get,
+ /// routing::service_method_router::get,
/// error_handling::HandleErrorExt,
/// http::StatusCode,
/// };
@@ -294,7 +301,7 @@ where
/// the prefix stripped.
///
/// ```rust
- /// use axum::{handler::get, http::Uri, Router};
+ /// use axum::{routing::get, http::Uri, Router};
///
/// let app = Router::new()
/// .route("/foo/*rest", get(|uri: Uri| async {
@@ -366,7 +373,7 @@ where
///
/// ```rust
/// use axum::{
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
/// use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit};
@@ -395,7 +402,7 @@ where
///
/// ```rust
/// use axum::{
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
/// use tower_http::trace::TraceLayer;
@@ -440,7 +447,7 @@ where
///
/// ```
/// use axum::{
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
///
@@ -470,7 +477,7 @@ where
/// ```
/// use axum::{
/// extract::ConnectInfo,
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
/// use std::net::SocketAddr;
@@ -496,7 +503,7 @@ where
/// ```
/// use axum::{
/// extract::connect_info::{ConnectInfo, Connected},
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
/// use hyper::server::conn::AddrStream;
@@ -555,7 +562,7 @@ where
///
/// ```
/// use axum::{
- /// handler::get,
+ /// routing::get,
/// Router,
/// };
/// #
diff --git a/src/service/mod.rs b/src/routing/service_method_router.rs
similarity index 74%
rename from src/service/mod.rs
rename to src/routing/service_method_router.rs
index 05e1006e..49c4d491 100644
--- a/src/service/mod.rs
+++ b/src/routing/service_method_router.rs
@@ -1,4 +1,4 @@
-//! Use Tower [`Service`]s to handle requests.
+//! Routing for [`Service`'s] based on HTTP methods.
//!
//! Most of the time applications will be written by composing
//! [handlers](crate::handler), however sometimes you might have some general
@@ -13,10 +13,9 @@
//! use tower_http::services::Redirect;
//! use axum::{
//! body::Body,
-//! handler::get,
+//! routing::{get, service_method_router as service},
//! http::Request,
//! Router,
-//! service,
//! };
//!
//! async fn handler(request: Request) { /* ... */ }
@@ -66,7 +65,7 @@
//!
//! ```rust
//! use axum::{
-//! handler::get,
+//! routing::get,
//! Router,
//! };
//! use tower::ServiceBuilder;
@@ -95,30 +94,36 @@
//!
//! [`Redirect`]: tower_http::services::Redirect
//! [load shed]: tower::load_shed
+//! [`Service`'s]: tower::Service
-use crate::BoxError;
use crate::{
- body::BoxBody,
+ body::{box_body, BoxBody},
routing::{EmptyRouter, MethodFilter},
+ util::{Either, EitherProj},
+ BoxError,
};
use bytes::Bytes;
-use http::{Request, Response};
+use futures_util::ready;
+use http::{Method, Request, Response};
+use http_body::Empty;
+use pin_project_lite::pin_project;
+use std::marker::PhantomData;
use std::{
- marker::PhantomData,
+ future::Future,
+ pin::Pin,
task::{Context, Poll},
};
+use tower::util::Oneshot;
use tower::ServiceExt as _;
use tower_service::Service;
-pub mod future;
-
/// Route requests with any standard HTTP method to the given service.
///
/// See [`get`] for an example.
///
/// Note that this only accepts the standard HTTP methods. If you need to
/// support non-standard methods you can route directly to a [`Service`].
-pub fn any(svc: S) -> OnMethod, B>
+pub fn any(svc: S) -> MethodRouter, B>
where
S: Service> + Clone,
{
@@ -128,7 +133,7 @@ where
/// Route `CONNECT` requests to the given service.
///
/// See [`get`] for an example.
-pub fn connect(svc: S) -> OnMethod, B>
+pub fn connect(svc: S) -> MethodRouter, B>
where
S: Service> + Clone,
{
@@ -138,7 +143,7 @@ where
/// Route `DELETE` requests to the given service.
///
/// See [`get`] for an example.
-pub fn delete(svc: S) -> OnMethod, B>
+pub fn delete(svc: S) -> MethodRouter, B>
where
S: Service> + Clone,
{
@@ -153,7 +158,7 @@ where
/// use axum::{
/// http::Request,
/// Router,
-/// service,
+/// routing::service_method_router as service,
/// };
/// use http::Response;
/// use std::convert::Infallible;
@@ -173,7 +178,7 @@ where
/// Note that `get` routes will also be called for `HEAD` requests but will have
/// the response body removed. Make sure to add explicit `HEAD` routes
/// afterwards.
-pub fn get(svc: S) -> OnMethod, B>
+pub fn get(svc: S) -> MethodRouter, B>
where
S: Service> + Clone,
{
@@ -183,7 +188,7 @@ where
/// Route `HEAD` requests to the given service.
///
/// See [`get`] for an example.
-pub fn head(svc: S) -> OnMethod, B>
+pub fn head(svc: S) -> MethodRouter, B>
where
S: Service> + Clone,
{
@@ -193,7 +198,7 @@ where
/// Route `OPTIONS` requests to the given service.
///
/// See [`get`] for an example.
-pub fn options(svc: S) -> OnMethod, B>
+pub fn options(svc: S) -> MethodRouter, B>
where
S: Service> + Clone,
{
@@ -203,7 +208,7 @@ where
/// Route `PATCH` requests to the given service.
///
/// See [`get`] for an example.
-pub fn patch(svc: S) -> OnMethod, B>
+pub fn patch(svc: S) -> MethodRouter, B>
where
S: Service> + Clone,
{
@@ -213,7 +218,7 @@ where
/// Route `POST` requests to the given service.
///
/// See [`get`] for an example.
-pub fn post(svc: S) -> OnMethod, B>
+pub fn post