summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Pedersen <david.pdrsn@gmail.com>2023-03-22 23:42:14 +0100
committerDavid Pedersen <david.pdrsn@gmail.com>2023-04-21 17:45:31 +0200
commitc97967252de9741b602f400dc2b25c8a33216039 (patch)
treece0100aa4c7221025824122fbea6077ef3cf60f3
parent6703f8634c33ad9dd3ae1afb4460b99ad26ccd49 (diff)
Add `serve` function and remove `Server` re-export (#1868)
-rw-r--r--axum-extra/src/extract/query.rs4
-rw-r--r--axum-extra/src/lib.rs2
-rw-r--r--axum-extra/src/protobuf.rs8
-rw-r--r--axum-macros/src/lib.rs18
-rw-r--r--axum/CHANGELOG.md3
-rw-r--r--axum/Cargo.toml5
-rw-r--r--axum/README.md9
-rw-r--r--axum/benches/benches.rs4
-rw-r--r--axum/src/body/stream_body.rs4
-rw-r--r--axum/src/docs/error_handling.md12
-rw-r--r--axum/src/docs/extract.md32
-rw-r--r--axum/src/docs/method_routing/layer.md4
-rw-r--r--axum/src/docs/method_routing/route_layer.md4
-rw-r--r--axum/src/docs/middleware.md18
-rw-r--r--axum/src/docs/routing/into_make_service_with_connect_info.md22
-rw-r--r--axum/src/docs/routing/nest.md12
-rw-r--r--axum/src/docs/routing/route.md12
-rw-r--r--axum/src/docs/routing/route_layer.md4
-rw-r--r--axum/src/docs/routing/route_service.md8
-rw-r--r--axum/src/docs/routing/with_state.md40
-rw-r--r--axum/src/extension.rs4
-rw-r--r--axum/src/extract/connect_info.rs53
-rw-r--r--axum/src/extract/matched_path.rs4
-rw-r--r--axum/src/extract/multipart.rs4
-rw-r--r--axum/src/extract/path/mod.rs16
-rw-r--r--axum/src/extract/query.rs4
-rw-r--r--axum/src/extract/raw_form.rs4
-rw-r--r--axum/src/extract/raw_query.rs4
-rw-r--r--axum/src/extract/request_parts.rs8
-rw-r--r--axum/src/extract/state.rs10
-rw-r--r--axum/src/extract/ws.rs19
-rw-r--r--axum/src/handler/mod.rs4
-rw-r--r--axum/src/handler/service.rs41
-rw-r--r--axum/src/json.rs8
-rw-r--r--axum/src/lib.rs40
-rw-r--r--axum/src/middleware/from_extractor.rs4
-rw-r--r--axum/src/routing/method_routing.rs87
-rw-r--r--axum/src/routing/mod.rs26
-rw-r--r--axum/src/serve.rs234
-rw-r--r--axum/src/test_helpers/mod.rs2
-rw-r--r--axum/src/test_helpers/test_client.rs29
-rw-r--r--axum/src/typed_header.rs4
-rw-r--r--deny.toml2
-rw-r--r--examples/anyhow-error-response/src/main.rs8
-rw-r--r--examples/chat/src/main.rs8
-rw-r--r--examples/consume-body-in-extractor-or-middleware/src/main.rs8
-rw-r--r--examples/cors/src/main.rs6
-rw-r--r--examples/customize-extractor-error/src/main.rs8
-rw-r--r--examples/customize-path-rejection/src/main.rs8
-rw-r--r--examples/error-handling-and-dependency-injection/src/main.rs9
-rw-r--r--examples/form/src/main.rs10
-rw-r--r--examples/global-404-handler/src/main.rs8
-rw-r--r--examples/graceful-shutdown/Cargo.toml1
-rw-r--r--examples/graceful-shutdown/src/main.rs2
-rw-r--r--examples/handle-head-request/src/main.rs8
-rw-r--r--examples/hello-world/src/main.rs8
-rw-r--r--examples/http-proxy/src/main.rs2
-rw-r--r--examples/jwt/src/main.rs10
-rw-r--r--examples/key-value-store/src/main.rs8
-rw-r--r--examples/listen-multiple-addrs/src/main.rs2
-rw-r--r--examples/multipart-form/src/main.rs8
-rw-r--r--examples/oauth/src/main.rs10
-rw-r--r--examples/parse-body-based-on-content-type/src/main.rs8
-rw-r--r--examples/print-request-response/src/main.rs8
-rw-r--r--examples/prometheus-metrics/src/main.rs19
-rw-r--r--examples/query-params-with-empty-strings/src/main.rs5
-rw-r--r--examples/readme/src/main.rs9
-rw-r--r--examples/rest-grpc-multiplex/src/main.rs2
-rw-r--r--examples/reverse-proxy/src/main.rs15
-rw-r--r--examples/routes-and-handlers-close-together/src/main.rs8
-rw-r--r--examples/sessions/src/main.rs8
-rw-r--r--examples/sqlx-postgres/src/main.rs12
-rw-r--r--examples/sse/src/main.rs9
-rw-r--r--examples/static-file-server/src/main.rs6
-rw-r--r--examples/stream-to-file/src/main.rs9
-rw-r--r--examples/templates/src/main.rs8
-rw-r--r--examples/testing-websockets/src/main.rs19
-rw-r--r--examples/testing/src/main.rs20
-rw-r--r--examples/tls-rustls/src/main.rs7
-rw-r--r--examples/todos/src/main.rs8
-rw-r--r--examples/tokio-postgres/src/main.rs10
-rw-r--r--examples/tracing-aka-logging/src/main.rs12
-rw-r--r--examples/unix-domain-socket/src/main.rs2
-rw-r--r--examples/validator/src/main.rs12
-rw-r--r--examples/versioning/src/main.rs9
-rw-r--r--examples/websockets/src/main.rs12
86 files changed, 641 insertions, 564 deletions
diff --git a/axum-extra/src/extract/query.rs b/axum-extra/src/extract/query.rs
index 43be2ec7..304d72b8 100644
--- a/axum-extra/src/extract/query.rs
+++ b/axum-extra/src/extract/query.rs
@@ -41,9 +41,7 @@ use std::fmt;
/// }
///
/// let app = Router::new().route("/list_things", get(list_things));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// If the query string cannot be parsed it will reject the request with a `400
diff --git a/axum-extra/src/lib.rs b/axum-extra/src/lib.rs
index a964de37..6a63a23c 100644
--- a/axum-extra/src/lib.rs
+++ b/axum-extra/src/lib.rs
@@ -105,7 +105,7 @@ use axum_macros::__private_axum_test as test;
pub(crate) mod test_helpers {
#![allow(unused_imports)]
- use axum::{body::HttpBody, BoxError, Router};
+ use axum::{extract::Request, response::Response, serve};
mod test_client {
#![allow(dead_code)]
diff --git a/axum-extra/src/protobuf.rs b/axum-extra/src/protobuf.rs
index ce08bd71..e3c4b51d 100644
--- a/axum-extra/src/protobuf.rs
+++ b/axum-extra/src/protobuf.rs
@@ -45,9 +45,7 @@ use prost::Message;
/// }
///
/// let app = Router::new().route("/users", post(create_user));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// # As response
@@ -85,9 +83,7 @@ use prost::Message;
/// }
///
/// let app = Router::new().route("/users/:id", get(get_user));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
#[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(docsrs, doc(cfg(feature = "protobuf")))]
diff --git a/axum-macros/src/lib.rs b/axum-macros/src/lib.rs
index ac8c5b6e..269665f8 100644
--- a/axum-macros/src/lib.rs
+++ b/axum-macros/src/lib.rs
@@ -416,10 +416,8 @@ pub fn derive_from_request_parts(item: TokenStream) -> TokenStream {
/// async fn main() {
/// let app = Router::new().route("/", get(handler));
///
-/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
-/// .serve(app.into_make_service())
-/// .await
-/// .unwrap();
+/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+/// axum::serve(listener, app).await.unwrap();
/// }
///
/// fn handler() -> &'static str {
@@ -438,10 +436,8 @@ pub fn derive_from_request_parts(item: TokenStream) -> TokenStream {
/// # async fn main() {
/// # let app = Router::new().route("/", get(handler));
/// #
-/// # axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
-/// # .serve(app.into_make_service())
-/// # .await
-/// # .unwrap();
+/// # let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+/// # axum::serve(listener, app).await.unwrap();
/// # }
/// #
/// #[debug_handler]
@@ -468,10 +464,8 @@ pub fn derive_from_request_parts(item: TokenStream) -> TokenStream {
/// # async {
/// let app = Router::new().route("/", get(handler));
///
-/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
-/// .serve(app.into_make_service())
-/// .await
-/// .unwrap();
+/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+/// axum::serve(listener, app).await.unwrap();
/// # };
/// }
///
diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md
index c877677e..59e5be21 100644
--- a/axum/CHANGELOG.md
+++ b/axum/CHANGELOG.md
@@ -40,12 +40,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **added:** Add `axum::extract::Request` type alias where the body is `axum::body::Body` ([#1789])
- **added:** Add `Router::as_service` and `Router::into_service` to workaround
type inference issues when calling `ServiceExt` methods on a `Router` ([#1835])
+- **breaking:** Removed `axum::Server` as it was removed in hyper 1.0. Instead
+ use `axum::serve(listener, service)` or hyper/hyper-util for more configuration options ([#1868])
[#1664]: https://github.com/tokio-rs/axum/pull/1664
[#1751]: https://github.com/tokio-rs/axum/pull/1751
[#1762]: https://github.com/tokio-rs/axum/pull/1762
[#1835]: https://github.com/tokio-rs/axum/pull/1835
[#1789]: https://github.com/tokio-rs/axum/pull/1789
+[#1868]: https://github.com/tokio-rs/axum/pull/1868
# 0.6.16 (18. April, 2023)
diff --git a/axum/Cargo.toml b/axum/Cargo.toml
index 61f834c8..89f00612 100644
--- a/axum/Cargo.toml
+++ b/axum/Cargo.toml
@@ -51,6 +51,10 @@ tower = { version = "0.4.13", default-features = false, features = ["util"] }
tower-layer = "0.3.2"
tower-service = "0.3"
+# wont need this when axum uses http-body 1.0
+hyper1 = { package = "hyper", version = "1.0.0-rc.3", features = ["server", "http1"] }
+tower-hyper-http-body-compat = { version = "0.1.4", features = ["server", "http1"] }
+
# optional dependencies
axum-macros = { path = "../axum-macros", version = "0.3.7", optional = true }
base64 = { version = "0.21.0", optional = true }
@@ -192,6 +196,7 @@ allowed = [
"http_body",
"hyper",
"serde",
+ "tokio",
"tower_layer",
"tower_service",
]
diff --git a/axum/README.md b/axum/README.md
index ab07aafc..b5948864 100644
--- a/axum/README.md
+++ b/axum/README.md
@@ -54,13 +54,8 @@ async fn main() {
.route("/users", post(create_user));
// run our app with hyper
- // `axum::Server` is a re-export of `hyper::Server`
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
- .await
- .unwrap();
+ let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+ axum::serve(listener, app).await.unwrap();
}
// basic handler that responds with a static string
diff --git a/axum/benches/benches.rs b/axum/benches/benches.rs
index c3b9c19e..4fad5e3d 100644
--- a/axum/benches/benches.rs
+++ b/axum/benches/benches.rs
@@ -1,7 +1,7 @@
use axum::{
extract::State,
routing::{get, post},
- Extension, Json, Router, Server,
+ Extension, Json, Router,
};
use hyper::server::conn::AddrIncoming;
use serde::{Deserialize, Serialize};
@@ -164,7 +164,7 @@ impl BenchmarkBuilder {
std::thread::spawn(move || {
rt.block_on(async move {
let incoming = AddrIncoming::from_listener(listener).unwrap();
- Server::builder(incoming)
+ hyper::Server::builder(incoming)
.serve(app.into_make_service())
.await
.unwrap();
diff --git a/axum/src/body/stream_body.rs b/axum/src/body/stream_body.rs
index 6331567a..933d1051 100644
--- a/axum/src/body/stream_body.rs
+++ b/axum/src/body/stream_body.rs
@@ -47,9 +47,7 @@ pin_project! {
/// }
///
/// let app = Router::new().route("/", get(handler));
- /// # async {
- /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
- /// # };
+ /// # let _: Router = app;
/// ```
///
/// [`Stream`]: futures_util::stream::Stream
diff --git a/axum/src/docs/error_handling.md b/axum/src/docs/error_handling.md
index 45c768c6..b9abce6f 100644
--- a/axum/src/docs/error_handling.md
+++ b/axum/src/docs/error_handling.md
@@ -85,9 +85,7 @@ async fn handle_anyhow_error(err: anyhow::Error) -> (StatusCode, String) {
format!("Something went wrong: {}", err),
)
}
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Applying fallible middleware
@@ -129,9 +127,7 @@ async fn handle_timeout_error(err: BoxError) -> (StatusCode, String) {
)
}
}
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Running extractors for error handling
@@ -171,9 +167,7 @@ async fn handle_timeout_error(
format!("`{} {}` failed with {}", method, uri, err),
)
}
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
[`tower::Service`]: `tower::Service`
diff --git a/axum/src/docs/extract.md b/axum/src/docs/extract.md
index e5e188a9..07268e59 100644
--- a/axum/src/docs/extract.md
+++ b/axum/src/docs/extract.md
@@ -47,9 +47,7 @@ async fn create_user(Json(payload): Json<CreateUser>) {
}
let app = Router::new().route("/users", post(create_user));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Common extractors
@@ -111,9 +109,7 @@ let app = Router::new()
.route("/json", post(json))
.route("/request", post(request))
.route("/extension", post(extension));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Applying multiple extractors
@@ -151,9 +147,7 @@ async fn get_user_things(
// ...
}
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# The order of extractors
@@ -253,9 +247,7 @@ async fn create_user(payload: Option<Json<Value>>) {
}
let app = Router::new().route("/users", post(create_user));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
Wrapping extractors in `Result` makes them optional and gives you the reason
@@ -295,9 +287,7 @@ async fn create_user(payload: Result<Json<Value>, JsonRejection>) {
}
let app = Router::new().route("/users", post(create_user));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Customizing extractor responses
@@ -452,9 +442,7 @@ async fn handler(ExtractUserAgent(user_agent): ExtractUserAgent) {
}
let app = Router::new().route("/foo", get(handler));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
## Implementing `FromRequest`
@@ -501,9 +489,7 @@ async fn handler(ValidatedBody(body): ValidatedBody) {
}
let app = Router::new().route("/foo", get(handler));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
## Cannot implement both `FromRequest` and `FromRequestParts`
@@ -624,9 +610,7 @@ async fn handler(user: AuthenticatedUser) {
let state = State { /* ... */ };
let app = Router::new().route("/", get(handler)).layer(Extension(state));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Request body limits
diff --git a/axum/src/docs/method_routing/layer.md b/axum/src/docs/method_routing/layer.md
index cdf6f933..7ceadd4d 100644
--- a/axum/src/docs/method_routing/layer.md
+++ b/axum/src/docs/method_routing/layer.md
@@ -23,7 +23,5 @@ let app = Router::new().route(
// All requests to `GET /` will be sent through `ConcurrencyLimitLayer`
get(hander).layer(ConcurrencyLimitLayer::new(64)),
);
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
diff --git a/axum/src/docs/method_routing/route_layer.md b/axum/src/docs/method_routing/route_layer.md
index f497e8b1..7a7ff36a 100644
--- a/axum/src/docs/method_routing/route_layer.md
+++ b/axum/src/docs/method_routing/route_layer.md
@@ -28,7 +28,5 @@ let app = Router::new().route(
// `GET /foo` with a valid token will receive `200 OK`
// `GET /foo` with a invalid token will receive `401 Unauthorized`
// `POST /FOO` with a invalid token will receive `405 Method Not Allowed`
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
diff --git a/axum/src/docs/middleware.md b/axum/src/docs/middleware.md
index 6aca7a3e..70eda706 100644
--- a/axum/src/docs/middleware.md
+++ b/axum/src/docs/middleware.md
@@ -55,9 +55,7 @@ let app = Router::new()
.layer(TraceLayer::new_for_http())
.layer(Extension(State {}))
);
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Commonly used middleware
@@ -319,9 +317,7 @@ let app = Router::new()
}))
.layer(TimeoutLayer::new(Duration::from_secs(10)))
);
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
See [`error_handling`](crate::error_handling) for more details on axum's error
@@ -376,9 +372,7 @@ let app = Router::new().route("/", get(handler));
let app = ServiceBuilder::new()
.layer(some_backpressure_sensitive_middleware)
.service(app);
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
However when applying middleware around your whole application in this way
@@ -563,10 +557,8 @@ let app = Router::new();
let app_with_middleware = middleware.layer(app);
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(app_with_middleware.into_make_service())
- .await
- .unwrap();
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, app_with_middleware.into_make_service()).await.unwrap();
# };
```
diff --git a/axum/src/docs/routing/into_make_service_with_connect_info.md b/axum/src/docs/routing/into_make_service_with_connect_info.md
index 05ee750c..67dd6524 100644
--- a/axum/src/docs/routing/into_make_service_with_connect_info.md
+++ b/axum/src/docs/routing/into_make_service_with_connect_info.md
@@ -21,12 +21,8 @@ async fn handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> String {
}
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(
- app.into_make_service_with_connect_info::<SocketAddr>()
- )
- .await
- .expect("server failed");
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>()).await.unwrap();
# };
```
@@ -36,9 +32,9 @@ You can implement custom a [`Connected`] like so:
use axum::{
extract::connect_info::{ConnectInfo, Connected},
routing::get,
+ serve::IncomingStream,
Router,
};
-use hyper::server::conn::AddrStream;
let app = Router::new().route("/", get(handler));
@@ -53,8 +49,8 @@ struct MyConnectInfo {
// ...
}
-impl Connected<&AddrStream> for MyConnectInfo {
- fn connect_info(target: &AddrStream) -> Self {
+impl Connected<IncomingStream<'_>> for MyConnectInfo {
+ fn connect_info(target: IncomingStream<'_>) -> Self {
MyConnectInfo {
// ...
}
@@ -62,12 +58,8 @@ impl Connected<&AddrStream> for MyConnectInfo {
}
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(
- app.into_make_service_with_connect_info::<MyConnectInfo>()
- )
- .await
- .expect("server failed");
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, app.into_make_service_with_connect_info::<MyConnectInfo>()).await.unwrap();
# };
```
diff --git a/axum/src/docs/routing/nest.md b/axum/src/docs/routing/nest.md
index b40d0fc9..c3f7308f 100644
--- a/axum/src/docs/routing/nest.md
+++ b/axum/src/docs/routing/nest.md
@@ -24,9 +24,7 @@ let app = Router::new().nest("/api", api_routes);
// Our app now accepts
// - GET /api/users/:id
// - POST /api/teams
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# How the URI changes
@@ -59,9 +57,7 @@ async fn users_get(Path(params): Path<HashMap<String, String>>) {
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();
-# };
+# let _: Router = app;
```
# Differences from wildcard routes
@@ -83,9 +79,7 @@ let app = Router::new()
// `uri` will contain `/foo`
}))
.nest("/bar", nested_router);
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Fallbacks
diff --git a/axum/src/docs/routing/route.md b/axum/src/docs/routing/route.md
index ae425142..394ae59b 100644
--- a/axum/src/docs/routing/route.md
+++ b/axum/src/docs/routing/route.md
@@ -77,9 +77,7 @@ async fn get_root() {}
async fn post_root() {}
async fn delete_root() {}
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# More examples
@@ -105,9 +103,7 @@ async fn show_user(Path(id): Path<u64>) {}
async fn do_users_action(Path((version, id)): Path<(String, u64)>) {}
async fn serve_asset(Path(path): Path<String>) {}
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
# Panics
@@ -120,9 +116,7 @@ use axum::{routing::get, Router};
let app = Router::new()
.route("/", get(|| async {}))
.route("/", get(|| async {}));
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
The static route `/foo` and the dynamic route `/:key` are not considered to
diff --git a/axum/src/docs/routing/route_layer.md b/axum/src/docs/routing/route_layer.md
index fe5b8faa..5e60eaf5 100644
--- a/axum/src/docs/routing/route_layer.md
+++ b/axum/src/docs/routing/route_layer.md
@@ -26,7 +26,5 @@ let app = Router::new()
// `GET /foo` with a valid token will receive `200 OK`
// `GET /foo` with a invalid token will receive `401 Unauthorized`
// `GET /not-found` with a invalid token will receive `404 Not Found`
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
diff --git a/axum/src/docs/routing/route_service.md b/axum/src/docs/routing/route_service.md
index 190e0183..7f016105 100644
--- a/axum/src/docs/routing/route_service.md
+++ b/axum/src/docs/routing/route_service.md
@@ -43,9 +43,7 @@ let app = Router::new()
"/static/Cargo.toml",
ServeFile::new("Cargo.toml"),
);
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
Routing to arbitrary services in this way has complications for backpressure
@@ -64,9 +62,7 @@ let app = Router::new().route_service(
"/",
Router::new().route("/foo", get(|| async {})),
);
-# async {
-# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-# };
+# let _: Router = app;
```
Use [`Router::nest`] instead.
diff --git a/axum/src/docs/routing/with_state.md b/axum/src/docs/routing/with_state.md
index 3f9c8151..bece920f 100644
--- a/axum/src/docs/routing/with_state.md
+++ b/axum/src/docs/routing/with_state.md
@@ -13,9 +13,8 @@ let routes = Router::new()
.with_state(AppState {});
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(routes.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, routes).await.unwrap();
# };
```
@@ -40,9 +39,8 @@ fn routes() -> Router<AppState> {
let routes = routes().with_state(AppState {});
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(routes.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, routes).await.unwrap();
# };
```
@@ -64,9 +62,8 @@ fn routes(state: AppState) -> Router {
let routes = routes(AppState {});
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(routes.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, routes).await.unwrap();
# };
```
@@ -92,9 +89,8 @@ fn routes<S>(state: AppState) -> Router<S> {
let routes = Router::new().nest("/api", routes(AppState {}));
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(routes.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, routes).await.unwrap();
# };
```
@@ -133,9 +129,8 @@ let router: Router<()> = router.with_state(AppState {});
// You cannot call `into_make_service` on a `Router<AppState>`
// because it is still missing an `AppState`.
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(router.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, router).await.unwrap();
# };
```
@@ -163,9 +158,8 @@ let final_router: Router<()> = string_router.with_state("foo".to_owned());
// Since we have a `Router<()>` we can run it.
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(final_router.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, final_router).await.unwrap();
# };
```
@@ -190,9 +184,8 @@ let app = routes(AppState {});
// We can only call `Router::into_make_service` on a `Router<()>`
// but `app` is a `Router<AppState>`
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(app.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, app).await.unwrap();
# };
```
@@ -214,9 +207,8 @@ let app = routes(AppState {});
// We can now call `Router::into_make_service`
# async {
-axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(app.into_make_service())
- .await;
+let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+axum::serve(listener, app).await.unwrap();
# };
```
diff --git a/axum/src/extension.rs b/axum/src/extension.rs
index d66c9466..42f208c4 100644
--- a/axum/src/extension.rs
+++ b/axum/src/extension.rs
@@ -40,9 +40,7 @@ use tower_service::Service;
/// // Add middleware that inserts the state into all incoming request's
/// // extensions.
/// .layer(Extension(state));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// If the extension is missing it will reject the request with a `500 Internal
diff --git a/axum/src/extract/connect_info.rs b/axum/src/extract/connect_info.rs
index f22b8981..216022e8 100644
--- a/axum/src/extract/connect_info.rs
+++ b/axum/src/extract/connect_info.rs
@@ -5,7 +5,7 @@
//! [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info
use super::{Extension, FromRequestParts};
-use crate::middleware::AddExtension;
+use crate::{middleware::AddExtension, serve::IncomingStream};
use async_trait::async_trait;
use http::request::Parts;
use hyper::server::conn::AddrStream;
@@ -89,6 +89,12 @@ impl Connected<&AddrStream> for SocketAddr {
}
}
+impl Connected<IncomingStream<'_>> for SocketAddr {
+ fn connect_info(target: IncomingStream<'_>) -> Self {
+ target.remote_addr()
+ }
+}
+
impl<S, C, T> Service<T> for IntoMakeServiceWithConnectInfo<S, C>
where
S: Clone,
@@ -213,8 +219,9 @@ where
#[cfg(test)]
mod tests {
use super::*;
- use crate::{routing::get, test_helpers::TestClient, Router, Server};
- use std::net::{SocketAddr, TcpListener};
+ use crate::{routing::get, test_helpers::TestClient, Router};
+ use std::net::SocketAddr;
+ use tokio::net::TcpListener;
#[crate::test]
async fn socket_addr() {
@@ -222,17 +229,19 @@ mod tests {
format!("{addr}")
}
- let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let (tx, rx) = tokio::sync::oneshot::channel();
tokio::spawn(async move {
let app = Router::new().route("/", get(handler));
- let server = Server::from_tcp(listener)
- .unwrap()
- .serve(app.into_make_service_with_connect_info::<SocketAddr>());
tx.send(()).unwrap();
- server.await.expect("server error");
+ crate::serve(
+ listener,
+ app.into_make_service_with_connect_info::<SocketAddr>(),
+ )
+ .await
+ .unwrap();
});
rx.await.unwrap();
@@ -250,8 +259,8 @@ mod tests {
value: &'static str,
}
- impl Connected<&AddrStream> for MyConnectInfo {
- fn connect_info(_target: &AddrStream) -> Self {
+ impl Connected<IncomingStream<'_>> for MyConnectInfo {
+ fn connect_info(_target: IncomingStream<'_>) -> Self {
Self {
value: "it worked!",
}
@@ -262,17 +271,19 @@ mod tests {
addr.value
}
- let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let (tx, rx) = tokio::sync::oneshot::channel();
tokio::spawn(async move {
let app = Router::new().route("/", get(handler));
- let server = Server::from_tcp(listener)
- .unwrap()
- .serve(app.into_make_service_with_connect_info::<MyConnectInfo>());
tx.send(()).unwrap();
- server.await.expect("server error");
+ crate::serve(
+ listener,
+ app.into_make_service_with_connect_info::<MyConnectInfo>(),
+ )
+ .await
+ .unwrap();
});
rx.await.unwrap();
@@ -306,7 +317,7 @@ mod tests {
format!("{addr}")
}
- let listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
tokio::spawn(async move {
@@ -314,10 +325,12 @@ mod tests {
.route("/", get(handler))
.layer(MockConnectInfo(SocketAddr::from(([0, 0, 0, 0], 1337))));
- let server = Server::from_tcp(listener)
- .unwrap()
- .serve(app.into_make_service_with_connect_info::<SocketAddr>());
- server.await.expect("server error");
+ crate::serve(
+ listener,
+ app.into_make_service_with_connect_info::<SocketAddr>(),
+ )
+ .await
+ .unwrap();
});
let client = reqwest::Client::new();
diff --git a/axum/src/extract/matched_path.rs b/axum/src/extract/matched_path.rs
index 50224c32..8cef754f 100644
--- a/axum/src/extract/matched_path.rs
+++ b/axum/src/extract/matched_path.rs
@@ -20,9 +20,7 @@ use std::{collections::HashMap, sync::Arc};
/// // `path` will be "/users/:id"
/// })
/// );
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// # Accessing `MatchedPath` via extensions
diff --git a/axum/src/extract/multipart.rs b/axum/src/extract/multipart.rs
index ae8f9da1..c8478d09 100644
--- a/axum/src/extract/multipart.rs
+++ b/axum/src/extract/multipart.rs
@@ -48,9 +48,7 @@ use std::{
/// }
///
/// let app = Router::new().route("/upload", post(upload));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
#[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
#[derive(Debug)]
diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs
index 189e476e..5f7c7107 100644
--- a/axum/src/extract/path/mod.rs
+++ b/axum/src/extract/path/mod.rs
@@ -42,9 +42,7 @@ use std::{fmt, sync::Arc};
/// }
///
/// 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();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// If the path contains only one parameter, then you can omit the tuple.
@@ -62,9 +60,7 @@ use std::{fmt, sync::Arc};
/// }
///
/// let app = Router::new().route("/users/:user_id", get(user_info));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// Path segments also can be deserialized into any type that implements
@@ -103,9 +99,7 @@ use std::{fmt, sync::Arc};
/// "/users/:user_id/team/:team_id",
/// get(users_teams_show).post(users_teams_create),
/// );
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// If you wish to capture all path parameters you can use `HashMap` or `Vec`:
@@ -132,9 +126,7 @@ use std::{fmt, sync::Arc};
///
/// let app = Router::new()
/// .route("/users/:user_id/team/:team_id", get(params_map).post(params_vec));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// # Providing detailed rejection output
diff --git a/axum/src/extract/query.rs b/axum/src/extract/query.rs
index 49efe8cb..81b28b61 100644
--- a/axum/src/extract/query.rs
+++ b/axum/src/extract/query.rs
@@ -32,9 +32,7 @@ use serde::de::DeserializeOwned;
/// }
///
/// let app = Router::new().route("/list_things", get(list_things));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// If the query string cannot be parsed it will reject the request with a `400
diff --git a/axum/src/extract/raw_form.rs b/axum/src/extract/raw_form.rs
index b1a6f973..f9c7d357 100644
--- a/axum/src/extract/raw_form.rs
+++ b/axum/src/extract/raw_form.rs
@@ -25,9 +25,7 @@ use super::{
/// async fn handler(RawForm(form): RawForm) {}
///
/// let app = Router::new().route("/", get(handler));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
#[derive(Debug)]
pub struct RawForm(pub Bytes);
diff --git a/axum/src/extract/raw_query.rs b/axum/src/extract/raw_query.rs
index 98a60b09..d8c56f84 100644
--- a/axum/src/extract/raw_query.rs
+++ b/axum/src/extract/raw_query.rs
@@ -20,9 +20,7 @@ use std::convert::Infallible;
/// }
///
/// let app = Router::new().route("/users", get(handler));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
#[derive(Debug)]
pub struct RawQuery(pub Option<String>);
diff --git a/axum/src/extract/request_parts.rs b/axum/src/extract/request_parts.rs
index 7dfb2f26..9756665b 100644
--- a/axum/src/extract/request_parts.rs
+++ b/axum/src/extract/request_parts.rs
@@ -28,9 +28,7 @@ use std::convert::Infallible;
/// );
///
/// let app = Router::new().nest("/api", api_routes);
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// # Extracting via request extensions
@@ -65,9 +63,7 @@ use std::convert::Infallible;
/// );
///
/// let app = Router::new().nest("/api", api_routes);
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
#[cfg(feature = "original-uri")]
#[derive(Debug, Clone)]
diff --git a/axum/src/extract/state.rs b/axum/src/extract/state.rs
index e2307d39..1592a813 100644
--- a/axum/src/extract/state.rs
+++ b/axum/src/extract/state.rs
@@ -131,13 +131,11 @@ use std::{
/// let method_router_with_state = get(handler)
/// // provide the state so the handler can access it
/// .with_state(state);
+/// # let _: axum::routing::MethodRouter = method_router_with_state;
///
/// async fn handler(State(state): State<AppState>) {
/// // use `state`...
/// }
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(method_router_with_state.into_make_service()).await.unwrap();
-/// # };
/// ```
///
/// # With `Handler`
@@ -158,10 +156,8 @@ use std::{
/// let handler_with_state = handler.with_state(state);
///
/// # async {
-/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
-/// .serve(handler_with_state.into_make_service())
-/// .await
-/// .expect("server failed");
+/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+/// axum::serve(listener, handler_with_state.into_make_service()).await.unwrap();
/// # };
/// ```
///
diff --git a/axum/src/extract/ws.rs b/axum/src/extract/ws.rs
index d3a014ce..991ee0b8 100644
--- a/axum/src/extract/ws.rs
+++ b/axum/src/extract/ws.rs
@@ -31,9 +31,7 @@
//! }
//! }
//! }
-//! # async {
-//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-//! # };
+//! # let _: Router = app;
//! ```
//!
//! # Passing data and/or state to an `on_upgrade` callback
@@ -62,9 +60,7 @@
//! let app = Router::new()
//! .route("/ws", get(handler))
//! .with_state(AppState { /* ... */ });
-//! # async {
-//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-//! # };
+//! # let _: Router = app;
//! ```
//!
//! # Read and write concurrently
@@ -108,7 +104,6 @@ use http::{
request::Parts,
Method, StatusCode,
};
-use hyper::upgrade::{OnUpgrade, Upgraded};
use sha1::{Digest, Sha1};
use std::{
borrow::Cow,
@@ -137,7 +132,7 @@ pub struct WebSocketUpgrade<F = DefaultOnFailedUpgrade> {
/// The chosen protocol sent in the `Sec-WebSocket-Protocol` header of the response.
protocol: Option<HeaderValue>,
sec_websocket_key: HeaderValue,
- on_upgrade: OnUpgrade,
+ on_upgrade: hyper1::upgrade::OnUpgrade,
on_failed_upgrade: F,
sec_websocket_protocol: Option<HeaderValue>,
}
@@ -206,9 +201,7 @@ impl<F> WebSocketUpgrade<F> {
/// // ...
/// })
/// }
- /// # async {
- /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
- /// # };
+ /// # let _: Router = app;
/// ```
pub fn protocols<I>(mut self, protocols: I) -> Self
where
@@ -393,7 +386,7 @@ where
let on_upgrade = parts
.extensions
- .remove::<OnUpgrade>()
+ .remove::<hyper1::upgrade::OnUpgrade>()
.ok_or(ConnectionNotUpgradable)?;
let sec_websocket_protocol = parts.headers.get(header::SEC_WEBSOCKET_PROTOCOL).cloned();
@@ -436,7 +429,7 @@ fn header_contains(headers: &HeaderMap, key: HeaderName, value: &'static str) ->
/// See [the module level documentation](self) for more details.
#[derive(Debug)]
pub struct WebSocket {
- inner: WebSocketStream<Upgraded>,
+ inner: WebSocketStream<hyper1::upgrade::Upgraded>,
protocol: Option<HeaderValue>,
}
diff --git a/axum/src/handler/mod.rs b/axum/src/handler/mod.rs
index 69e7879c..d1370145 100644
--- a/axum/src/handler/mod.rs
+++ b/axum/src/handler/mod.rs
@@ -135,9 +135,7 @@ pub trait Handler<T, S>: Clone + Send + Sized + 'static {
///
/// let layered_handler = handler.layer(ConcurrencyLimitLayer::new(64));
/// let app = Router::new().route("/", get(layered_handler));
- /// # async {
- /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
- /// # };
+ /// # let _: Router = app;
/// ```
fn layer<L>(self, layer: L) -> Layered<L, Self, T, S>
where
diff --git a/axum/src/handler/service.rs b/axum/src/handler/service.rs
index 86b93afe..35974a4c 100644
--- a/axum/src/handler/service.rs
+++ b/axum/src/handler/service.rs
@@ -37,7 +37,6 @@ impl<H, T, S> HandlerService<H, T, S> {
///
/// ```rust
/// use axum::{
- /// Server,
/// handler::Handler,
/// extract::State,
/// http::{Uri, Method},
@@ -55,10 +54,8 @@ impl<H, T, S> HandlerService<H, T, S> {
/// let app = handler.with_state(AppState {});
///
/// # async {
- /// Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000)))
- /// .serve(app.into_make_service())
- /// .await?;
- /// # Ok::<_, hyper::Error>(())
+ /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+ /// axum::serve(listener, app.into_make_service()).await.unwrap();
/// # };
/// ```
///
@@ -74,7 +71,6 @@ impl<H, T, S> HandlerService<H, T, S> {
///
/// ```rust
/// use axum::{
- /// Server,
/// handler::Handler,
/// response::IntoResponse,
/// extract::{ConnectInfo, State},
@@ -94,10 +90,11 @@ impl<H, T, S> HandlerService<H, T, S> {
/// let app = handler.with_state(AppState {});
///
/// # async {
- /// Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000)))
- /// .serve(app.into_make_service_with_connect_info::<SocketAddr>())
- /// .await?;
- /// # Ok::<_, hyper::Error>(())
+ /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+ /// axum::serve(
+ /// listener,
+ /// app.into_make_service_with_connect_info::<SocketAddr>(),
+ /// ).await.unwrap();
/// # };
/// ```
///
@@ -179,3 +176,27 @@ where
super::future::IntoServiceFuture::new(future)
}
}
+
+// for `axum::serve(listener, handler)`
+#[cfg(feature = "tokio")]
+const _: () = {
+ use crate::serve::IncomingStream;
+
+ impl<H, T, S> Service<IncomingStream<'_>> for HandlerService<H, T, S>
+ where
+ H: Clone,
+ S: Clone,
+ {
+ type Response = Self;
+ type Error = Infallible;
+ type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
+
+ fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn call(&mut self, _req: IncomingStream<'_>) -> Self::Future {
+ std::future::ready(Ok(self.clone()))
+ }
+ }
+};
diff --git a/axum/src/json.rs b/axum/src/json.rs
index 2cab54e9..a78f0644 100644
--- a/axum/src/json.rs
+++ b/axum/src/json.rs
@@ -50,9 +50,7 @@ use serde::{de::DeserializeOwned, Serialize};
/// }
///
/// let app = Router::new().route("/users", post(create_user));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// When used as a response, it can serialize any type that implements [`serde::Serialize`] to
@@ -87,9 +85,7 @@ use serde::{de::DeserializeOwned, Serialize};
/// }
///
/// let app = Router::new().route("/users/:id", get(get_user));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
#[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
diff --git a/axum/src/lib.rs b/axum/src/lib.rs
index da60aef5..3813de14 100644
--- a/axum/src/lib.rs
+++ b/axum/src/lib.rs
@@ -53,11 +53,9 @@
//! // build our application with a single route
//! 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())
-//! .serve(app.into_make_service())
-//! .await
-//! .unwrap();
+//! // run it on localhost:3000
+//! let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+//! axum::serve(listener, app).await.unwrap();
//! }
//! ```
//!
@@ -82,9 +80,7 @@
//! async fn get_foo() {}
//! async fn post_foo() {}
//! async fn foo_bar() {}
-//! # async {
-//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-//! # };
+//! # let _: Router = app;
//! ```
//!
//! See [`Router`] for more details on routing.
@@ -145,9 +141,7 @@
//! let app = Router::new()
//! .route("/plain_text", get(plain_text))
//! .route("/json", get(json));
-//! # async {
-//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-//! # };
+//! # let _: Router = app;
//! ```
//!
//! See [`response`](crate::response) for more details on building responses.
@@ -202,9 +196,7 @@
//! ) {
//! // ...
//! }
-//! # async {
-//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-//! # };
+//! # let _: Router = app;
//! ```
//!
//! You should prefer using [`State`] if possible since it's more type safe. The downside is that
@@ -240,9 +232,7 @@
//! ) {
//! // ...
//! }
-//! # async {
-//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-//! # };
+//! # let _: Router = app;
//! ```
//!
//! The downside to this approach is that you'll get runtime errors
@@ -298,9 +288,7 @@
//! struct CreateUserPayload {
//! // ...
//! }
-//! # async {
-//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-//! # };
+//! # let _: Router = app;
//! ```
//!
//! The downside to this approach is that it's a little more verbose than using
@@ -356,7 +344,7 @@
//! `matched-path` | Enables capturing of every request's router path and the [`MatchedPath`] extractor | Yes
//! `multipart` | Enables parsing `multipart/form-data` requests with [`Multipart`] | No
//! `original-uri` | Enables capturing of every request's original URI and the [`OriginalUri`] extractor | Yes
-//! `tokio` | Enables `tokio` as a dependency and `axum::Server`, `SSE` and `extract::connect_info` types. | Yes
+//! `tokio` | Enables `tokio` as a dependency and `axum::serve`, `SSE` and `extract::connect_info` types. | Yes
//! `tower-log` | Enables `tower`'s `log` feature | Yes
//! `tracing` | Log rejections from built-in extractors | No
//! `ws` | Enables WebSockets support via [`extract::ws`] | No
@@ -377,7 +365,6 @@
//! [`Timeout`]: tower::timeout::Timeout
//! [examples]: https://github.com/tokio-rs/axum/tree/main/examples
//! [`Router::merge`]: crate::routing::Router::merge
-//! [`axum::Server`]: hyper::server::Server
//! [`Service`]: tower::Service
//! [`Service::poll_ready`]: tower::Service::poll_ready
//! [`Service`'s]: tower::Service
@@ -459,6 +446,8 @@ pub mod handler;
pub mod middleware;
pub mod response;
pub mod routing;
+#[cfg(feature = "tokio")]
+pub mod serve;
#[cfg(test)]
mod test_helpers;
@@ -470,9 +459,6 @@ pub use async_trait::async_trait;
pub use headers;
#[doc(no_inline)]
pub use http;
-#[cfg(feature = "tokio")]
-#[doc(no_inline)]
-pub use hyper::Server;
#[doc(inline)]
pub use self::extension::Extension;
@@ -496,6 +482,10 @@ pub use axum_core::{BoxError, Error, RequestExt, RequestPartsExt};
#[cfg(feature = "macros")]
pub use axum_macros::debug_handler;
+#[cfg(feature = "tokio")]
+#[doc(inline)]
+pub use self::serve::serve;
+
pub use self::service_ext::ServiceExt;
#[cfg(test)]
diff --git a/axum/src/middleware/from_extractor.rs b/axum/src/middleware/from_extractor.rs
index 8c9a2483..e120ffc1 100644
--- a/axum/src/middleware/from_extractor.rs
+++ b/axum/src/middleware/from_extractor.rs
@@ -84,9 +84,7 @@ use tower_service::Service;
/// .route("/foo", post(other_handler))
/// // The extractor will run before all routes
/// .route_layer(from_extractor::<RequireAuth>());
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// [`Bytes`]: bytes::Bytes
diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs
index 9040ee30..dc8f9ec0 100644
--- a/axum/src/routing/method_routing.rs
+++ b/axum/src/routing/method_routing.rs
@@ -48,9 +48,7 @@ macro_rules! top_level_service_fn {
///
/// // Requests to `GET /` will go to `service`.
/// let app = Router::new().route("/", get_service(service));
- /// # async {
- /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
- /// # };
+ /// # let _: Router = app;
/// ```
///
/// Note that `get` routes will also be called for `HEAD` requests but will have
@@ -109,9 +107,7 @@ macro_rules! top_level_handler_fn {
///
/// // 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();
- /// # };
+ /// # let _: Router = app;
/// ```
///
/// Note that `get` routes will also be called for `HEAD` requests but will have
@@ -180,9 +176,7 @@ macro_rules! chained_service_fn {
/// // Requests to `POST /` will go to `service` and `GET /` will go to
/// // `other_service`.
/// let app = Router::new().route("/", post_service(service).get_service(other_service));
- /// # async {
- /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
- /// # };
+ /// # let _: Router = app;
/// ```
///
/// Note that `get` routes will also be called for `HEAD` requests but will have
@@ -244,9 +238,7 @@ macro_rules! chained_handler_fn {
/// // Requests to `POST /` will go to `handler` and `GET /` 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();
- /// # };
+ /// # let _: Router = app;
/// ```
///
/// Note that `get` routes will also be called for `HEAD` requests but will have
@@ -316,9 +308,7 @@ top_level_service_fn!(trace_service, TRACE);
///
/// // Requests to `POST /` will go to `service`.
/// let app = Router::new().route("/", on_service(MethodFilter::POST, service));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
pub fn on_service<T, S>(filter: MethodFilter, svc: T) -> MethodRouter<S, T::Error>
where
@@ -350,9 +340,7 @@ where
///
/// // All requests to `/` will go to `service`.
/// let app = Router::new().route("/", any_service(service));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// Additional methods can still be chained:
@@ -379,9 +367,7 @@ where
///
/// // `POST /` goes to `other_service`. All other requests go to `service`
/// let app = Router::new().route("/", any_service(service).post_service(other_service));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
pub fn any_service<T, S>(svc: T) -> MethodRouter<S, T::Error>
where
@@ -419,9 +405,7 @@ top_level_handler_fn!(trace, TRACE);
///
/// // 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();
-/// # };
+/// # let _: Router = app;
/// ```
pub fn on<H, T, S>(filter: MethodFilter, handler: H) -> MethodRouter<S, Infallible>
where
@@ -446,9 +430,7 @@ where
///
/// // All requests to `/` will go to `handler`.
/// let app = Router::new().route("/", any(handler));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// Additional methods can still be chained:
@@ -465,9 +447,7 @@ where
///
/// // `POST /` goes to `other_handler`. All other requests go to `handler`
/// let app = Router::new().route("/", any(handler).post(other_handler));
-/// # async {
-/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
-/// # };
+/// # let _: Router = app;
/// ```
pub fn any<H, T, S>(handler: H) -> MethodRouter<S, Infallible>
where
@@ -587,9 +567,7 @@ where
/// // 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();
- /// # };
+ /// # let _: Router = app;
/// ```
#[track_caller]
pub fn on<H, T>(self, filter: MethodFilter, handler: H) -> Self
@@ -632,7 +610,6 @@ impl MethodRouter<(), Infallible> {
///
/// ```rust
/// use axum::{
- /// Server,
/// handler::Handler,
/// http::{Uri, Method},
/// response::IntoResponse,
@@ -647,10 +624,8 @@ impl MethodRouter<(), Infallible> {
/// let router = get(handler).post(handler);
///
/// # async {
- /// Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000)))
- /// .serve(router.into_make_service())
- /// .await?;
- /// # Ok::<_, hyper::Error>(())
+ /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+ /// axum::serve(listener, router.into_make_service()).await.unwrap();
/// # };
/// ```
///
@@ -666,7 +641,6 @@ impl MethodRouter<(), Infallible> {
///
/// ```rust
/// use axum::{
- /// Server,
/// handler::Handler,
/// response::IntoResponse,
/// extract::ConnectInfo,
@@ -681,10 +655,8 @@ impl MethodRouter<(), Infallible> {
/// let router = get(handler).post(handler);
///
/// # async {
- /// Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000)))
- /// .serve(router.into_make_service_with_connect_info::<SocketAddr>())
- /// .await?;
- /// # Ok::<_, hyper::Error>(())
+ /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+ /// axum::serve(listener, router.into_make_service()).await.unwrap();
/// # };
/// ```
///
@@ -758,9 +730,7 @@ where
///
/// // Requests to `DELETE /` will go to `service`
/// let app = Router::new().route("/", on_service(MethodFilter::DELETE, service));
- /// # async {
- /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
- /// # };
+ /// # let _: Router = app;
/// ```
#[track_caller]
pub fn on_service<T>(self, filter: MethodFilter, svc: T) -> Self
@@ -1261,6 +1231,26 @@ where
}
}
+// for `axum::serve(listener, router)`
+#[cfg(feature = "tokio")]
+const _: () = {
+ use crate::serve::IncomingStream;
+
+ impl Service<IncomingStream<'_>> for MethodRouter<()> {
+ type Response = Self;
+ type Error = Infallible;
+ type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
+
+ fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn call(&mut self, _req: IncomingStream<'_>) -> Self::Future {
+ std::future::ready(Ok(self.clone()))
+ }
+ }
+};
+
#[cfg(test)]
mod tests {
use super::*;
@@ -1361,7 +1351,7 @@ mod tests {
}
#[allow(dead_code)]
- fn buiding_complex_router() {
+ async fn buiding_complex_router() {
let app = crate::Router::new().route(
"/",
// use the all the things :bomb:
@@ -1380,7 +1370,8 @@ mod tests {
),
);
- crate::Server::bind(&"0.0.0.0:0".parse().unwrap()).serve(app.into_make_service());
+ let listener = tokio::net::TcpListener::bind("0.0.0.0:0").await.unwrap();
+ crate::serve(listener, app).await.unwrap();
}
#[crate::test]
diff --git a/axum/src/routing/mod.rs b/axum/src/routing/mod.rs
index 74660fe6..c45b823e 100644
--- a/axum/src/routing/mod.rs
+++ b/axum/src/routing/mod.rs
@@ -413,10 +413,8 @@ impl Router {
/// let app = Router::new().route("/", get(|| async { "Hi!" }));
///
/// # async {
- /// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- /// .serve(app.into_make_service())
- /// .await
- /// .expect("server failed");
+ /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+ /// axum::serve(listener, app).await.unwrap();
/// # };
/// ```
///
@@ -436,6 +434,26 @@ impl Router {
}
}
+// for `axum::serve(listener, router)`
+#[cfg(feature = "tokio")]
+const _: () = {
+ use crate::serve::IncomingStream;
+
+ impl Service<IncomingStream<'_>> for Router<()> {
+ type Response = Self;
+ type Error = Infallible;
+ type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
+
+ fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn call(&mut self, _req: IncomingStream<'_>) -> Self::Future {
+ std::future::ready(Ok(self.clone()))
+ }
+ }
+};
+
impl<B> Service<Request<B>> for Router<()>
where
B: HttpBody<Data = bytes::Bytes> + Send + 'static,
diff --git a/axum/src/serve.rs b/axum/src/serve.rs
new file mode 100644
index 00000000..83f529c8
--- /dev/null
+++ b/axum/src/serve.rs
@@ -0,0 +1,234 @@
+//! Serve services.
+
+use std::{convert::Infallible, io, net::SocketAddr};
+
+use axum_core::{body::Body, extract::Request, response::Response};
+use futures_util::{future::poll_fn, FutureExt};
+use hyper1::server::conn::http1;
+use tokio::net::{TcpListener, TcpStream};
+use tower_hyper_http_body_compat::{HttpBody04ToHttpBody1, HttpBody1ToHttpBody04};
+use tower_service::Service;
+
+/// Serve the service with the supplied listener.
+///
+/// This method of running a service is intentionally simple and doesn't support any configuration.
+/// Use hyper or hyper-util if you need configuration.
+///
+/// It only supports HTTP/1.
+///
+/// # Examples
+///
+/// Serving a [`Router`]:
+///
+/// ```
+/// use axum::{Router, routing::get};
+///
+/// # async {
+/// let router = Router::new().route("/", get(|| async { "Hello, World!" }));
+///
+/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+/// axum::serve(listener, router).await.unwrap();
+/// # };
+/// ```
+///
+/// See also [`Router::into_make_service_with_connect_info`].
+///
+/// Serving a [`MethodRouter`]:
+///
+/// ```
+/// use axum::routing::get;
+///
+/// # async {
+/// let router = get(|| async { "Hello, World!" });
+///
+/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+/// axum::serve(listener, router).await.unwrap();
+/// # };
+/// ```
+///
+/// See also [`MethodRouter::into_make_service_with_connect_info`].
+///
+/// Serving a [`Handler`]:
+///
+/// ```
+/// use axum::handler::HandlerWithoutStateExt;
+///
+/// # async {
+/// async fn handler() -> &'static str {
+/// "Hello, World!"
+/// }
+///
+/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
+/// axum::serve(listener, handler.into_make_service()).await.unwrap();
+/// # };
+/// ```
+///
+/// See also [`HandlerWithoutStateExt::into_make_service_with_connect_info`] and
+/// [`HandlerService::into_make_service_with_connect_info`].
+///
+/// [`Router`]: crate::Router
+/// [`Router::into_make_service_with_connect_info`]: crate::Router::into_make_service_with_connect_info
+/// [`MethodRouter`]: crate::routing::MethodRouter
+/// [`MethodRouter::into_make_service_with_connect_info`]: crate::routing::MethodRouter::into_make_service_with_connect_info
+/// [`Handler`]: crate::handler::Handler
+/// [`HandlerWithoutStateExt::into_make_service_with_connect_info`]: crate::handler::HandlerWithoutStateExt::into_make_service_with_connect_info
+/// [`HandlerService::into_make_service_with_connect_info`]: crate::handler::HandlerService::into_make_service_with_connect_info
+#[cfg(feature = "tokio")]
+pub async fn serve<M, S>(tcp_listener: TcpListener, mut make_service: M) -> io::Result<()>
+where
+ M: for<'a> Service<IncomingStream<'a>, Error = Infallible, Response = S>,
+ S: Service<Request, Response = Response, Error = Infallible> + Clone + Send + 'static,
+ S::Future: Send,
+{
+ loop {
+ let (tcp_stream, remote_addr) = tcp_listener.accept().await?;
+
+ poll_fn(|cx| make_service.poll_ready(cx))
+ .await
+ .unwrap_or_else(|err| match err {});
+
+ let mut service = make_service
+ .call(IncomingStream {
+ tcp_stream: &tcp_stream,
+ remote_addr,
+ })
+ .await
+ .unwrap_or_else(|err| match err {});
+
+ let service = hyper1::service::service_fn(move |req: Request<hyper1::body::Incoming>| {
+ let req = req.map(|body| {
+ // wont need this when axum uses http-body 1.0
+ let http_body_04 = HttpBody1ToHttpBody04::new(body);
+ Body::new(http_body_04)
+ });
+
+ // doing this saves cloning the service just to await the service being ready
+ //
+ // services like `Router` are always ready, so assume the service
+ // we're running here is also always ready...
+ match futures_util::future::poll_fn(|cx| service.poll_ready(cx)).now_or_never() {
+ Some(Ok(())) => {}
+ Some(Err(err)) => match err {},
+ None => {
+ // ...otherwise load shed
+ let mut res = Response::new(HttpBody04ToHttpBody1::new(Body::empty()));
+ *res.status_mut() = http::StatusCode::SERVICE_UNAVAILABLE;
+ return std::future::ready(Ok(res)).left_future();
+ }
+ }
+
+ let future = service.call(req);
+
+ async move {
+ let response = future
+ .await
+ .unwrap_or_else(|err| match err {})
+ // wont need this when axum uses http-body 1.0
+ .map(HttpBody04ToHttpBody1::new);
+
+ Ok::<_, Infallible>(response)
+ }
+ .right_future()
+ });
+
+ tokio::task::spawn(async move {
+ match http1::Builder::new()
+ .serve_connection(tcp_stream, service)
+ // for websockets
+ .with_upgrades()
+ .await
+ {
+ Ok(()) => {}
+ Err(_err) => {
+ // This error only appears when the client doesn't send a request and
+ // terminate the connection.
+ //
+ // If client sends one request then terminate connection whenever, it doesn't
+ // appear.
+ }
+ }
+ });
+ }
+}
+
+/// An incoming stream.
+///
+/// Used with [`serve`] and [`IntoMakeServiceWithConnectInfo`].
+///
+/// [`IntoMakeServiceWithConnectInfo`]: crate::extract::connect_info::IntoMakeServiceWithConnectInfo
+#[derive(Debug)]
+pub struct IncomingStream<'a> {
+ tcp_stream: &'a TcpStream,
+ remote_addr: SocketAddr,
+}
+
+impl IncomingStream<'_> {
+ /// Returns the local address that this stream is bound to.
+ pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
+ self.tcp_stream.local_addr()
+ }
+
+ /// Returns the remote address that this stream is bound to.
+ pub fn remote_addr(&self) -> SocketAddr {
+ self.remote_addr
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{
+ handler::{Handler, HandlerWithoutStateExt},
+ routing::get,
+ Router,
+ };
+
+ #[allow(dead_code, unused_must_use)]
+ async fn if_it_compiles_it_works() {
+ let router: Router = Router::new();
+
+ let addr = "0.0.0.0:0";
+
+ // router
+ serve(TcpListener::bind(addr).await.unwrap(), router.clone());
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ router.clone().into_make_service(),
+ );
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ router.into_make_service_with_connect_info::<SocketAddr>(),
+ );
+
+ // method router
+ serve(TcpListener::bind(addr).await.unwrap(), get(handler));
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ get(handler).into_make_service(),
+ );
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ get(handler).into_make_service_with_connect_info::<SocketAddr>(),
+ );
+
+ // handler
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ handler.into_service(),
+ );
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ handler.with_state(()),
+ );
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ handler.into_make_service(),
+ );
+ serve(
+ TcpListener::bind(addr).await.unwrap(),
+ handler.into_make_service_with_connect_info::<SocketAddr>(),
+ );
+ }
+
+ async fn handler() {}
+}
diff --git a/axum/src/test_helpers/mod.rs b/axum/src/test_helpers/mod.rs
index a8b4cf99..3bb1535e 100644
--- a/axum/src/test_helpers/mod.rs
+++ b/axum/src/test_helpers/mod.rs
@@ -1,6 +1,6 @@
#![allow(clippy::disallowed_names)]
-use crate::{body::HttpBody, BoxError};
+use crate::{extract::Request, response::Response, serve};
mod test_client;
pub(crate) use self::test_client::*;
diff --git a/axum/src/test_helpers/test_client.rs b/axum/src/test_helpers/test_client.rs
index fa052a00..9e1858cb 100644
--- a/axum/src/test_helpers/test_client.rs
+++ b/axum/src/test_helpers/test_client.rs
@@ -1,11 +1,11 @@
-use super::{BoxError, HttpBody};
+use super::{serve, Request, Response};
use bytes::Bytes;
use http::{
header::{HeaderName, HeaderValue},
- Request, StatusCode,
+ StatusCode,
};
-use hyper::Server;
-use std::net::{SocketAddr, TcpListener};
+use std::{convert::Infallible, net::SocketAddr};
+use tokio::net::TcpListener;
use tower::make::Shared;
use tower_service::Service;
@@ -15,25 +15,22 @@ pub(crate) struct TestClient {
}
impl TestClient {
- pub(crate) fn new<S, ResBody>(svc: S) -> Self
+ pub(crate) fn new<S>(svc: S) -> Self
where
- S: Service<Request<hyper::Body>, Response = http::Response<ResBody>>
- + Clone
- + Send
- + 'static,
- ResBody: HttpBody + Send + 'static,
- ResBody::Data: Send,
- ResBody::Error: Into<BoxError>,
+ S: Service<Request, Response = Response, Error = Infallible> + Clone + Send + 'static,
S::Future: Send,
- S::Error: Into<BoxError>,
{
- let listener = TcpListener::bind("127.0.0.1:0").expect("Could not bind ephemeral socket");
+ let std_listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
+ std_listener.set_nonblocking(true).unwrap();
+ let listener = TcpListener::from_std(std_listener).unwrap();
+
let addr = listener.local_addr().unwrap();
println!("Listening on {addr}");
tokio::spawn(async move {
- let server = Server::from_tcp(listener).unwrap().serve(Shared::new(svc));
- server.await.expect("server error");
+ serve(listener, Shared::new(svc))
+ .await
+ .expect("server error")
});
let client = reqwest::Client::builder()
diff --git a/axum/src/typed_header.rs b/axum/src/typed_header.rs
index 72b3d7e7..229cd06d 100644
--- a/axum/src/typed_header.rs
+++ b/axum/src/typed_header.rs
@@ -27,9 +27,7 @@ use std::convert::Infallible;
/// }
///
/// 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();
-/// # };
+/// # let _: Router = app;
/// ```
///
/// # As response
diff --git a/deny.toml b/deny.toml
index c543455c..9a3fd955 100644
--- a/deny.toml
+++ b/deny.toml
@@ -25,6 +25,8 @@ skip-tree = [
{ name = "spin" },
# lots still pulls in syn 1.x
{ name = "syn" },
+ # until 1.0 is out we're pulling in both 0.14 and 1.0-rc.x
+ { name = "hyper" },
]
[sources]
diff --git a/examples/anyhow-error-response/src/main.rs b/examples/anyhow-error-response/src/main.rs
index 68548313..b7a2416a 100644
--- a/examples/anyhow-error-response/src/main.rs
+++ b/examples/anyhow-error-response/src/main.rs
@@ -10,18 +10,16 @@ use axum::{
routing::get,
Router,
};
-use std::net::SocketAddr;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(handler));
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- println!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler() -> Result<(), AppError> {
diff --git a/examples/chat/src/main.rs b/examples/chat/src/main.rs
index 3b49c3e8..f7298c34 100644
--- a/examples/chat/src/main.rs
+++ b/examples/chat/src/main.rs
@@ -18,7 +18,6 @@ use axum::{
use futures::{sink::SinkExt, stream::StreamExt};
use std::{
collections::HashSet,
- net::SocketAddr,
sync::{Arc, Mutex},
};
use tokio::sync::broadcast;
@@ -53,12 +52,11 @@ async fn main() {
.route("/websocket", get(websocket_handler))
.with_state(app_state);
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn websocket_handler(
diff --git a/examples/consume-body-in-extractor-or-middleware/src/main.rs b/examples/consume-body-in-extractor-or-middleware/src/main.rs
index f1b2cbf7..fd63fcb1 100644
--- a/examples/consume-body-in-extractor-or-middleware/src/main.rs
+++ b/examples/consume-body-in-extractor-or-middleware/src/main.rs
@@ -14,7 +14,6 @@ use axum::{
routing::post,
Router,
};
-use std::net::SocketAddr;
use tower::ServiceBuilder;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -32,12 +31,11 @@ async fn main() {
.route("/", post(handler))
.layer(ServiceBuilder::new().layer(middleware::from_fn(print_request_body)));
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
// middleware that shows how to consume the request body upfront
diff --git a/examples/cors/src/main.rs b/examples/cors/src/main.rs
index a0a5e8d8..bbd19206 100644
--- a/examples/cors/src/main.rs
+++ b/examples/cors/src/main.rs
@@ -40,10 +40,8 @@ async fn main() {
async fn serve(app: Router, port: u16) {
let addr = SocketAddr::from(([127, 0, 0, 1], port));
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
- .await
- .unwrap();
+ let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
+ axum::serve(listener, app).await.unwrap();
}
async fn html() -> impl IntoResponse {
diff --git a/examples/customize-extractor-error/src/main.rs b/examples/customize-extractor-error/src/main.rs
index 893fbd14..e8820326 100644
--- a/examples/customize-extractor-error/src/main.rs
+++ b/examples/customize-extractor-error/src/main.rs
@@ -9,7 +9,6 @@ mod derive_from_request;
mod with_rejection;
use axum::{routing::post, Router};
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -29,10 +28,9 @@ async fn main() {
.route("/derive-from-request", post(derive_from_request::handler));
// Run our application
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
diff --git a/examples/customize-path-rejection/src/main.rs b/examples/customize-path-rejection/src/main.rs
index 3bcd91d3..fa382e4b 100644
--- a/examples/customize-path-rejection/src/main.rs
+++ b/examples/customize-path-rejection/src/main.rs
@@ -13,7 +13,6 @@ use axum::{
Router,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -30,12 +29,11 @@ async fn main() {
let app = Router::new().route("/users/:user_id/teams/:team_id", get(handler));
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- println!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler(Path(params): Path<Params>) -> impl IntoResponse {
diff --git a/examples/error-handling-and-dependency-injection/src/main.rs b/examples/error-handling-and-dependency-injection/src/main.rs
index f28ed4ff..a5bdad9e 100644
--- a/examples/error-handling-and-dependency-injection/src/main.rs
+++ b/examples/error-handling-and-dependency-injection/src/main.rs
@@ -17,7 +17,7 @@ use axum::{
};
use serde::{Deserialize, Serialize};
use serde_json::json;
-use std::{net::SocketAddr, sync::Arc};
+use std::sync::Arc;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use uuid::Uuid;
@@ -42,12 +42,11 @@ async fn main() {
.with_state(user_repo);
// Run our application
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
/// Handler for `GET /users/:id`.
diff --git a/examples/form/src/main.rs b/examples/form/src/main.rs
index 93a5ae13..3f9ed095 100644
--- a/examples/form/src/main.rs
+++ b/examples/form/src/main.rs
@@ -6,7 +6,6 @@
use axum::{extract::Form, response::Html, routing::get, Router};
use serde::Deserialize;
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -22,13 +21,12 @@ async fn main() {
// build our application with some routes
let app = Router::new().route("/", get(show_form).post(accept_form));
- // run it with hyper
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ // run it
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn show_form() -> Html<&'static str> {
diff --git a/examples/global-404-handler/src/main.rs b/examples/global-404-handler/src/main.rs
index 8eb14691..38b02943 100644
--- a/examples/global-404-handler/src/main.rs
+++ b/examples/global-404-handler/src/main.rs
@@ -10,7 +10,6 @@ use axum::{
routing::get,
Router,
};
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -30,12 +29,11 @@ async fn main() {
let app = app.fallback(handler_404);
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler() -> Html<&'static str> {
diff --git a/examples/graceful-shutdown/Cargo.toml b/examples/graceful-shutdown/Cargo.toml
index 19af3113..f287feeb 100644
--- a/examples/graceful-shutdown/Cargo.toml
+++ b/examples/graceful-shutdown/Cargo.toml
@@ -6,4 +6,5 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
+hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1.0", features = ["full"] }
diff --git a/examples/graceful-shutdown/src/main.rs b/examples/graceful-shutdown/src/main.rs
index 3704889a..dabfee16 100644
--- a/examples/graceful-shutdown/src/main.rs
+++ b/examples/graceful-shutdown/src/main.rs
@@ -17,7 +17,7 @@ async fn main() {
// run it
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("listening on {}", addr);
- axum::Server::bind(&addr)
+ hyper::Server::bind(&addr)
.serve(app.into_make_service())
.with_graceful_shutdown(shutdown_signal())
.await
diff --git a/examples/handle-head-request/src/main.rs b/examples/handle-head-request/src/main.rs
index 5b0db264..d49d88ef 100644
--- a/examples/handle-head-request/src/main.rs
+++ b/examples/handle-head-request/src/main.rs
@@ -6,7 +6,6 @@
use axum::response::{IntoResponse, Response};
use axum::{http, routing::get, Router};
-use std::net::SocketAddr;
fn app() -> Router {
Router::new().route("/get-head", get(get_head_handler))
@@ -14,12 +13,11 @@ fn app() -> Router {
#[tokio::main]
async fn main() {
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
-
- axum::Server::bind(&addr)
- .serve(app().into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app()).await.unwrap();
}
// GET routes will also be called for HEAD requests but will have the response body removed.
diff --git a/examples/hello-world/src/main.rs b/examples/hello-world/src/main.rs
index 466caceb..de018335 100644
--- a/examples/hello-world/src/main.rs
+++ b/examples/hello-world/src/main.rs
@@ -5,7 +5,6 @@
//! ```
use axum::{response::Html, routing::get, Router};
-use std::net::SocketAddr;
#[tokio::main]
async fn main() {
@@ -13,12 +12,11 @@ async fn main() {
let app = Router::new().route("/", get(handler));
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- println!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler() -> Html<&'static str> {
diff --git a/examples/http-proxy/src/main.rs b/examples/http-proxy/src/main.rs
index 08845ca9..1abf3bbf 100644
--- a/examples/http-proxy/src/main.rs
+++ b/examples/http-proxy/src/main.rs
@@ -52,7 +52,7 @@ async fn main() {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
+ hyper::Server::bind(&addr)
.http1_preserve_header_case(true)
.http1_title_case_headers(true)
.serve(Shared::new(service))
diff --git a/examples/jwt/src/main.rs b/examples/jwt/src/main.rs
index 4ee20d4b..a6f8bffa 100644
--- a/examples/jwt/src/main.rs
+++ b/examples/jwt/src/main.rs
@@ -19,7 +19,7 @@ use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use serde_json::json;
-use std::{fmt::Display, net::SocketAddr};
+use std::fmt::Display;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
// Quick instructions
@@ -67,13 +67,11 @@ async fn main() {
.route("/protected", get(protected))
.route("/authorize", post(authorize));
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
-
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn protected(claims: Claims) -> Result<String, AuthError> {
diff --git a/examples/key-value-store/src/main.rs b/examples/key-value-store/src/main.rs
index ccf21825..b22802cb 100644
--- a/examples/key-value-store/src/main.rs
+++ b/examples/key-value-store/src/main.rs
@@ -19,7 +19,6 @@ use axum::{
use std::{
borrow::Cow,
collections::HashMap,
- net::SocketAddr,
sync::{Arc, RwLock},
time::Duration,
};
@@ -74,12 +73,11 @@ async fn main() {
.with_state(Arc::clone(&shared_state));
// Run our app with hyper
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
type SharedState = Arc<RwLock<AppState>>;
diff --git a/examples/listen-multiple-addrs/src/main.rs b/examples/listen-multiple-addrs/src/main.rs
index f292c1d6..fed70daa 100644
--- a/examples/listen-multiple-addrs/src/main.rs
+++ b/examples/listen-multiple-addrs/src/main.rs
@@ -28,7 +28,7 @@ async fn main() {
b: incoming_v6,
};
- axum::Server::builder(combined)
+ hyper::Server::builder(combined)
.serve(app.into_make_service())
.await
.unwrap();
diff --git a/examples/multipart-form/src/main.rs b/examples/multipart-form/src/main.rs
index 31f2887e..f8c0d96b 100644
--- a/examples/multipart-form/src/main.rs
+++ b/examples/multipart-form/src/main.rs
@@ -10,7 +10,6 @@ use axum::{
routing::get,
Router,
};
-use std::net::SocketAddr;
use tower_http::limit::RequestBodyLimitLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -34,12 +33,11 @@ async fn main() {
.layer(tower_http::trace::TraceLayer::new_for_http());
// run it with hyper
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn show_form() -> Html<&'static str> {
diff --git a/examples/oauth/src/main.rs b/examples/oauth/src/main.rs
index 1a01570f..40a039bc 100644
--- a/examples/oauth/src/main.rs
+++ b/examples/oauth/src/main.rs
@@ -25,7 +25,7 @@ use oauth2::{
ClientSecret, CsrfToken, RedirectUrl, Scope, TokenResponse, TokenUrl,
};
use serde::{Deserialize, Serialize};
-use std::{env, net::SocketAddr};
+use std::env;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
static COOKIE_NAME: &str = "SESSION";
@@ -56,13 +56,11 @@ async fn main() {
.route("/logout", get(logout))
.with_state(app_state);
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
-
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
#[derive(Clone)]
diff --git a/examples/parse-body-based-on-content-type/src/main.rs b/examples/parse-body-based-on-content-type/src/main.rs
index 9ee26c6a..bae4ec1d 100644
--- a/examples/parse-body-based-on-content-type/src/main.rs
+++ b/examples/parse-body-based-on-content-type/src/main.rs
@@ -15,7 +15,6 @@ use axum::{
Form, Json, RequestExt, Router,
};
use serde::{Deserialize, Serialize};
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -31,12 +30,11 @@ async fn main() {
let app = Router::new().route("/", post(handler));
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
#[derive(Debug, Serialize, Deserialize)]
diff --git a/examples/print-request-response/src/main.rs b/examples/print-request-response/src/main.rs
index 4703c058..1348d026 100644
--- a/examples/print-request-response/src/main.rs
+++ b/examples/print-request-response/src/main.rs
@@ -13,7 +13,6 @@ use axum::{
routing::post,
Router,
};
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -30,12 +29,11 @@ async fn main() {
.route("/", post(|| async move { "Hello from `POST /`" }))
.layer(middleware::from_fn(print_request_response));
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn print_request_response(
diff --git a/examples/prometheus-metrics/src/main.rs b/examples/prometheus-metrics/src/main.rs
index 675310be..b90c384f 100644
--- a/examples/prometheus-metrics/src/main.rs
+++ b/examples/prometheus-metrics/src/main.rs
@@ -17,7 +17,6 @@ use axum::{
use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle};
use std::{
future::ready,
- net::SocketAddr,
time::{Duration, Instant},
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -42,24 +41,22 @@ fn main_app() -> Router {
async fn start_main_server() {
let app = main_app();
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
- .unwrap()
+ .unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn start_metrics_server() {
let app = metrics_app();
// NOTE: expose metrics enpoint on a different port
- let addr = SocketAddr::from(([127, 0, 0, 1], 3001));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3001")
.await
- .unwrap()
+ .unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
#[tokio::main]
diff --git a/examples/query-params-with-empty-strings/src/main.rs b/examples/query-params-with-empty-strings/src/main.rs
index aa424643..19117c4e 100644
--- a/examples/query-params-with-empty-strings/src/main.rs
+++ b/examples/query-params-with-empty-strings/src/main.rs
@@ -10,10 +10,11 @@ use std::{fmt, str::FromStr};
#[tokio::main]
async fn main() {
- axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
- .serve(app().into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app()).await.unwrap();
}
fn app() -> Router {
diff --git a/examples/readme/src/main.rs b/examples/readme/src/main.rs
index bdcb8945..cd2120cb 100644
--- a/examples/readme/src/main.rs
+++ b/examples/readme/src/main.rs
@@ -11,7 +11,6 @@ use axum::{
Json, Router,
};
use serde::{Deserialize, Serialize};
-use std::net::SocketAddr;
#[tokio::main]
async fn main() {
@@ -26,13 +25,11 @@ async fn main() {
.route("/users", post(create_user));
// run our app with hyper
- // `axum::Server` is a re-export of `hyper::Server`
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
// basic handler that responds with a static string
diff --git a/examples/rest-grpc-multiplex/src/main.rs b/examples/rest-grpc-multiplex/src/main.rs
index f804f6ae..b7f0ab02 100644
--- a/examples/rest-grpc-multiplex/src/main.rs
+++ b/examples/rest-grpc-multiplex/src/main.rs
@@ -75,7 +75,7 @@ async fn main() {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
+ hyper::Server::bind(&addr)
.serve(tower::make::Shared::new(service))
.await
.unwrap();
diff --git a/examples/reverse-proxy/src/main.rs b/examples/reverse-proxy/src/main.rs
index a01947c6..875a3a5a 100644
--- a/examples/reverse-proxy/src/main.rs
+++ b/examples/reverse-proxy/src/main.rs
@@ -16,7 +16,6 @@ use axum::{
Router,
};
use hyper::client::HttpConnector;
-use std::net::SocketAddr;
type Client = hyper::client::Client<HttpConnector, Body>;
@@ -28,12 +27,11 @@ async fn main() {
let app = Router::new().route("/", get(handler)).with_state(client);
- let addr = SocketAddr::from(([127, 0, 0, 1], 4000));
- println!("reverse proxy listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:4000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler(State(client): State<Client>, mut req: Request) -> Response {
@@ -54,10 +52,9 @@ async fn handler(State(client): State<Client>, mut req: Request) -> Response {
async fn server() {
let app = Router::new().route("/", get(|| async { "Hello, world!" }));
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- println!("server listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
diff --git a/examples/routes-and-handlers-close-together/src/main.rs b/examples/routes-and-handlers-close-together/src/main.rs
index 75320d09..50721e70 100644
--- a/examples/routes-and-handlers-close-together/src/main.rs
+++ b/examples/routes-and-handlers-close-together/src/main.rs
@@ -8,7 +8,6 @@ use axum::{
routing::{get, post, MethodRouter},
Router,
};
-use std::net::SocketAddr;
#[tokio::main]
async fn main() {
@@ -17,12 +16,11 @@ async fn main() {
.merge(get_foo())
.merge(post_foo());
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- println!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
fn root() -> Router {
diff --git a/examples/sessions/src/main.rs b/examples/sessions/src/main.rs
index 9bea9c1b..fcac6c56 100644
--- a/examples/sessions/src/main.rs
+++ b/examples/sessions/src/main.rs
@@ -21,7 +21,6 @@ use axum::{
};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use uuid::Uuid;
@@ -42,12 +41,11 @@ async fn main() {
let app = Router::new().route("/", get(handler)).with_state(store);
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler(user_id: UserIdFromSession) -> impl IntoResponse {
diff --git a/examples/sqlx-postgres/src/main.rs b/examples/sqlx-postgres/src/main.rs
index 8e3353b9..e9553037 100644
--- a/examples/sqlx-postgres/src/main.rs
+++ b/examples/sqlx-postgres/src/main.rs
@@ -21,9 +21,10 @@ use axum::{
Router,
};
use sqlx::postgres::{PgPool, PgPoolOptions};
+use tokio::net::TcpListener;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
-use std::{net::SocketAddr, time::Duration};
+use std::time::Duration;
#[tokio::main]
async fn main() {
@@ -55,12 +56,9 @@ async fn main() {
.with_state(pool);
// run it with hyper
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
- .await
- .unwrap();
+ let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
// we can extract the connection pool with `State`
diff --git a/examples/sse/src/main.rs b/examples/sse/src/main.rs
index dab5a565..52888133 100644
--- a/examples/sse/src/main.rs
+++ b/examples/sse/src/main.rs
@@ -11,7 +11,7 @@ use axum::{
Router,
};
use futures::stream::{self, Stream};
-use std::{convert::Infallible, net::SocketAddr, path::PathBuf, time::Duration};
+use std::{convert::Infallible, path::PathBuf, time::Duration};
use tokio_stream::StreamExt as _;
use tower_http::{services::ServeDir, trace::TraceLayer};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -37,12 +37,11 @@ async fn main() {
.layer(TraceLayer::new_for_http());
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn sse_handler(
diff --git a/examples/static-file-server/src/main.rs b/examples/static-file-server/src/main.rs
index 3a3a2414..3aa7a9a8 100644
--- a/examples/static-file-server/src/main.rs
+++ b/examples/static-file-server/src/main.rs
@@ -103,9 +103,9 @@ fn calling_serve_dir_from_a_handler() -> Router {
async fn serve(app: Router, port: u16) {
let addr = SocketAddr::from(([127, 0, 0, 1], port));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.layer(TraceLayer::new_for_http()).into_make_service())
+ let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app.layer(TraceLayer::new_for_http()))
.await
.unwrap();
}
diff --git a/examples/stream-to-file/src/main.rs b/examples/stream-to-file/src/main.rs
index 2d514162..02164d4e 100644
--- a/examples/stream-to-file/src/main.rs
+++ b/examples/stream-to-file/src/main.rs
@@ -13,7 +13,7 @@ use axum::{
BoxError, Router,
};
use futures::{Stream, TryStreamExt};
-use std::{io, net::SocketAddr};
+use std::io;
use tokio::{fs::File, io::BufWriter};
use tokio_util::io::StreamReader;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -39,12 +39,11 @@ async fn main() {
.route("/", get(show_form).post(accept_form))
.route("/file/:file_name", post(save_request_body));
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
// Handler that streams the request body to a file.
diff --git a/examples/templates/src/main.rs b/examples/templates/src/main.rs
index d7e01a94..1abdb33e 100644
--- a/examples/templates/src/main.rs
+++ b/examples/templates/src/main.rs
@@ -12,7 +12,6 @@ use axum::{
routing::get,
Router,
};
-use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -29,12 +28,11 @@ async fn main() {
let app = Router::new().route("/greet/:name", get(greet));
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn greet(extract::Path(name): extract::Path<String>) -> impl IntoResponse {
diff --git a/examples/testing-websockets/src/main.rs b/examples/testing-websockets/src/main.rs
index b778115c..954168b1 100644
--- a/examples/testing-websockets/src/main.rs
+++ b/examples/testing-websockets/src/main.rs
@@ -14,16 +14,14 @@ use axum::{
Router,
};
use futures::{Sink, SinkExt, Stream, StreamExt};
-use std::net::SocketAddr;
#[tokio::main]
async fn main() {
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- println!("listening on {addr}");
- axum::Server::bind(&addr)
- .serve(app().into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ println!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app()).await.unwrap();
}
fn app() -> Router {
@@ -94,17 +92,18 @@ where
#[cfg(test)]
mod tests {
use super::*;
- use std::net::Ipv4Addr;
+ use std::net::{Ipv4Addr, SocketAddr};
use tokio_tungstenite::tungstenite;
// We can integration test one handler by running the server in a background task and
// connecting to it like any other client would.
#[tokio::test]
async fn integration_test() {
- let server = axum::Server::bind(&SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)))
- .serve(app().into_make_service());
- let addr = server.local_addr();
- tokio::spawn(server);
+ let listener = tokio::net::TcpListener::bind(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)))
+ .await
+ .unwrap();
+ let addr = listener.local_addr().unwrap();
+ tokio::spawn(axum::serve(listener, app()));
let (mut socket, _response) =
tokio_tungstenite::connect_async(format!("ws://{addr}/integration-testable"))
diff --git a/examples/testing/src/main.rs b/examples/testing/src/main.rs
index 5f7dbc07..99cc0402 100644
--- a/examples/testing/src/main.rs
+++ b/examples/testing/src/main.rs
@@ -24,14 +24,11 @@ async fn main() {
.with(tracing_subscriber::fmt::layer())
.init();
- let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000));
-
- tracing::debug!("listening on {}", addr);
-
- axum::Server::bind(&addr)
- .serve(app().into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app()).await.unwrap();
}
/// Having a function that produces our app makes it easy to call it from tests
@@ -63,7 +60,8 @@ mod tests {
http::{self, Request, StatusCode},
};
use serde_json::{json, Value};
- use std::net::{SocketAddr, TcpListener};
+ use std::net::SocketAddr;
+ use tokio::net::TcpListener;
use tower::Service; // for `call`
use tower::ServiceExt; // for `oneshot` and `ready`
@@ -131,15 +129,11 @@ mod tests {
// You can also spawn a server and talk to it like any other HTTP server:
#[tokio::test]
async fn the_real_deal() {
- let listener = TcpListener::bind("0.0.0.0:0".parse::<SocketAddr>().unwrap()).unwrap();
+ let listener = TcpListener::bind("0.0.0.0:0").await.unwrap();
let addr = listener.local_addr().unwrap();
tokio::spawn(async move {
- axum::Server::from_tcp(listener)
- .unwrap()
- .serve(app().into_make_service())
- .await
- .unwrap();
+ axum::serve(listener, app()).await.unwrap();
});
let client = hyper::Client::new();
diff --git a/examples/tls-rustls/src/main.rs b/examples/tls-rustls/src/main.rs
index 5034cf31..860f56b5 100644
--- a/examples/tls-rustls/src/main.rs
+++ b/examples/tls-rustls/src/main.rs
@@ -93,10 +93,9 @@ async fn redirect_http_to_https(ports: Ports) {
};
let addr = SocketAddr::from(([127, 0, 0, 1], ports.http));
- tracing::debug!("http redirect listening on {}", addr);
-
- axum::Server::bind(&addr)
- .serve(redirect.into_make_service())
+ let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, redirect.into_make_service())
.await
.unwrap();
}
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index 4463bfa4..9e08876d 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -24,7 +24,6 @@ use axum::{
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
- net::SocketAddr,
sync::{Arc, RwLock},
time::Duration,
};
@@ -68,12 +67,11 @@ async fn main() {
)
.with_state(db);
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
// The query parameters for todos index
diff --git a/examples/tokio-postgres/src/main.rs b/examples/tokio-postgres/src/main.rs
index 77c4c112..effc0320 100644
--- a/examples/tokio-postgres/src/main.rs
+++ b/examples/tokio-postgres/src/main.rs
@@ -13,7 +13,6 @@ use axum::{
};
use bb8::{Pool, PooledConnection};
use bb8_postgres::PostgresConnectionManager;
-use std::net::SocketAddr;
use tokio_postgres::NoTls;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -41,13 +40,12 @@ async fn main() {
)
.with_state(pool);
- // run it with hyper
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ // run it
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
type ConnectionPool = Pool<PostgresConnectionManager<NoTls>>;
diff --git a/examples/tracing-aka-logging/src/main.rs b/examples/tracing-aka-logging/src/main.rs
index 6b4524ac..74a2055a 100644
--- a/examples/tracing-aka-logging/src/main.rs
+++ b/examples/tracing-aka-logging/src/main.rs
@@ -12,7 +12,8 @@ use axum::{
routing::get,
Router,
};
-use std::{net::SocketAddr, time::Duration};
+use std::time::Duration;
+use tokio::net::TcpListener;
use tower_http::{classify::ServerErrorsFailureClass, trace::TraceLayer};
use tracing::{info_span, Span};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
@@ -80,12 +81,9 @@ async fn main() {
);
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
- .await
- .unwrap();
+ let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler() -> Html<&'static str> {
diff --git a/examples/unix-domain-socket/src/main.rs b/examples/unix-domain-socket/src/main.rs
index 0a3d3f0d..ce350720 100644
--- a/examples/unix-domain-socket/src/main.rs
+++ b/examples/unix-domain-socket/src/main.rs
@@ -63,7 +63,7 @@ mod unix {
tokio::spawn(async {
let app = Router::new().route("/", get(handler));
- axum::Server::builder(ServerAccept { uds })
+ hyper::Server::builder(ServerAccept { uds })
.serve(app.into_make_service_with_connect_info::<UdsConnectInfo>())
.await
.unwrap();
diff --git a/examples/validator/src/main.rs b/examples/validator/src/main.rs
index 4f4f6239..a6a25b85 100644
--- a/examples/validator/src/main.rs
+++ b/examples/validator/src/main.rs
@@ -19,8 +19,8 @@ use axum::{
Router,
};
use serde::{de::DeserializeOwned, Deserialize};
-use std::net::SocketAddr;
use thiserror::Error;
+use tokio::net::TcpListener;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use validator::Validate;
@@ -38,13 +38,9 @@ async fn main() {
let app = Router::new().route("/", get(handler));
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
-
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
- .await
- .unwrap();
+ let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
#[derive(Debug, Deserialize, Validate)]
diff --git a/examples/versioning/src/main.rs b/examples/versioning/src/main.rs
index fd3f6668..b5324d69 100644
--- a/examples/versioning/src/main.rs
+++ b/examples/versioning/src/main.rs
@@ -12,7 +12,7 @@ use axum::{
routing::get,
RequestPartsExt, Router,
};
-use std::{collections::HashMap, net::SocketAddr};
+use std::collections::HashMap;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
@@ -29,12 +29,11 @@ async fn main() {
let app = Router::new().route("/:version/foo", get(handler));
// run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(listener, app).await.unwrap();
}
async fn handler(version: Version) {
diff --git a/examples/websockets/src/main.rs b/examples/websockets/src/main.rs
index 73993c15..e13182bb 100644
--- a/examples/websockets/src/main.rs
+++ b/examples/websockets/src/main.rs
@@ -66,12 +66,16 @@ async fn main() {
);
// run it with hyper
- let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
- tracing::debug!("listening on {}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service_with_connect_info::<SocketAddr>())
+ let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
+ tracing::debug!("listening on {}", listener.local_addr().unwrap());
+ axum::serve(
+ listener,
+ app.into_make_service_with_connect_info::<SocketAddr>(),
+ )
+ .await
+ .unwrap();
}
/// The handler for the HTTP request (this gets called when the HTTP GET lands at the start