Add serve function and remove Server re-export (#1868)

This commit is contained in:
David Pedersen 2023-03-22 23:42:14 +01:00
parent 6703f8634c
commit c97967252d
86 changed files with 641 additions and 564 deletions

View file

@ -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

View file

@ -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)]

View file

@ -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")))]

View file

@ -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();
/// # };
/// }
///

View file

@ -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)

View file

@ -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",
]

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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`

View file

@ -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

View file

@ -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;
```

View file

@ -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;
```

View file

@ -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();
# };
```

View file

@ -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();
# };
```

View file

@ -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

View file

@ -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

View file

@ -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;
```

View file

@ -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.

View file

@ -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();
# };
```

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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)]

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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>);

View file

@ -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)]

View file

@ -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();
/// # };
/// ```
///

View file

@ -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>,
}

View file

@ -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

View file

@ -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()))
}
}
};

View file

@ -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")))]

View file

@ -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)]

View file

@ -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

View file

@ -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]

View file

@ -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,

234
axum/src/serve.rs Normal file
View file

@ -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() {}
}

View file

@ -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::*;

View file

@ -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()

View file

@ -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

View file

@ -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]

View file

@ -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> {

View file

@ -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(

View file

@ -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

View file

@ -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 {

View file

@ -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();
}

View file

@ -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 {

View file

@ -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`.

View file

@ -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> {

View file

@ -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> {

View file

@ -6,4 +6,5 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1.0", features = ["full"] }

View file

@ -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

View file

@ -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.

View file

@ -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> {

View file

@ -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))

View file

@ -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> {

View file

@ -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>>;

View file

@ -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();

View file

@ -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> {

View file

@ -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)]

View file

@ -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)]

View file

@ -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(

View file

@ -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]

View file

@ -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 {

View file

@ -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

View file

@ -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();

View file

@ -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();
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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`

View file

@ -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(

View file

@ -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();
}

View file

@ -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.

View file

@ -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 {

View file

@ -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"))

View file

@ -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();

View file

@ -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();
}

View file

@ -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

View file

@ -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>>;

View file

@ -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> {

View file

@ -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();

View file

@ -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)]

View file

@ -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) {

View file

@ -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