Merge branch 'main' into main

This commit is contained in:
Zheng Li 2024-09-28 18:44:10 +08:00 committed by GitHub
commit 2077c89b2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 309 additions and 245 deletions

View file

@ -28,7 +28,6 @@ If your project isn't listed here and you would like it to be, please feel free
- [aide](https://docs.rs/aide): Code-first Open API documentation generator with [axum integration](https://docs.rs/aide/latest/aide/axum/index.html).
- [axum-typed-routing](https://docs.rs/axum-typed-routing/latest/axum_typed_routing/): Statically typed routing macros with OpenAPI generation using aide.
- [axum-jsonschema](https://docs.rs/axum-jsonschema/): A `Json<T>` extractor that does JSON schema validation of requests.
- [tower-sessions](https://docs.rs/tower-sessions): Cookie-based sessions.
- [axum-login](https://docs.rs/axum-login): Session-based user authentication for axum.
- [axum-csrf-sync-pattern](https://crates.io/crates/axum-csrf-sync-pattern): A middleware implementing CSRF STP for AJAX backends and API endpoints.
- [axum-otel-metrics](https://github.com/ttys3/axum-otel-metrics/): A axum OpenTelemetry Metrics middleware with prometheus exporter supported.
@ -105,6 +104,7 @@ If your project isn't listed here and you would like it to be, please feel free
- [Introduction to axum]: YouTube playlist
- [Rust Axum Full Course]: YouTube video
- [Deploying Axum projects with Shuttle]
- [API Development with Rust](https://rust-api.dev/docs/front-matter/preface/): REST APIs based on Axum
[axum-tutorial]: https://github.com/programatik29/axum-tutorial
[axum-tutorial-website]: https://programatik29.github.io/axum-tutorial/

View file

@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# 0.4.5
- **fixed:** Compile errors from the internal `__log_rejection` macro under
certain Cargo feature combinations between axum crates ([#2933])
[#2933]: https://github.com/tokio-rs/axum/pull/2933
# 0.4.4
- **added:** Derive `Clone` and `Copy` for `AppendHeaders` ([#2776])

View file

@ -9,7 +9,7 @@ license = "MIT"
name = "axum-core"
readme = "README.md"
repository = "https://github.com/tokio-rs/axum"
version = "0.4.4" # remember to also bump the version that axum and axum-extra depend on
version = "0.4.5" # remember to also bump the version that axum and axum-extra depend on
[features]
tracing = ["dep:tracing"]
@ -54,6 +54,9 @@ allowed = [
"http_body",
]
[package.metadata.cargo-machete]
ignored = ["tower-http"] # See __private_docs feature
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

View file

@ -50,6 +50,11 @@
#[macro_use]
pub(crate) mod macros;
#[doc(hidden)] // macro helpers
pub mod __private {
#[cfg(feature = "tracing")]
pub use tracing;
}
mod error;
mod ext_traits;

View file

@ -9,12 +9,12 @@ macro_rules! __log_rejection {
status = $status:expr,
) => {
{
tracing::event!(
$crate::__private::tracing::event!(
target: "axum::rejection",
tracing::Level::TRACE,
$crate::__private::tracing::Level::TRACE,
status = $status.as_u16(),
body = $body_text,
rejection_type = std::any::type_name::<$ty>(),
rejection_type = ::std::any::type_name::<$ty>(),
"rejecting request",
);
}

View file

@ -34,13 +34,13 @@ json-lines = [
multipart = ["dep:multer"]
protobuf = ["dep:prost"]
query = ["dep:serde_html_form"]
tracing = ["dep:tracing", "axum-core/tracing", "axum/tracing"]
tracing = ["axum-core/tracing", "axum/tracing"]
typed-header = ["dep:headers"]
typed-routing = ["dep:axum-macros", "dep:percent-encoding", "dep:serde_html_form", "dep:form_urlencoded"]
[dependencies]
axum = { path = "../axum", version = "0.7.6", default-features = false }
axum-core = { path = "../axum-core", version = "0.4.4" }
axum = { path = "../axum", version = "0.7.7", default-features = false }
axum-core = { path = "../axum-core", version = "0.4.5" }
bytes = "1.1.0"
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
http = "1.0.0"

View file

@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# Unreleased
- **breaking:** The tuple and tuple_struct `Path` extractor deserializers now check that the number of parameters matches the tuple length exactly ([#2931])
[#2931]: https://github.com/tokio-rs/axum/pull/2931
# 0.7.7
- **change**: Remove manual tables of content from the documentation, since
rustdoc now generates tables of content in the sidebar ([#2921])
[#2921]: https://github.com/tokio-rs/axum/pull/2921
# 0.7.6
- **change:** Avoid cloning `Arc` during deserialization of `Path`

View file

@ -1,6 +1,6 @@
[package]
name = "axum"
version = "0.7.6"
version = "0.7.7"
categories = ["asynchronous", "network-programming", "web-programming::http-server"]
description = "Web framework that focuses on ergonomics and modularity"
edition = "2021"
@ -41,7 +41,7 @@ ws = ["dep:hyper", "tokio", "dep:tokio-tungstenite", "dep:sha1", "dep:base64"]
__private_docs = ["tower/full", "dep:tower-http"]
[dependencies]
axum-core = { path = "../axum-core", version = "0.4.4" }
axum-core = { path = "../axum-core", version = "0.4.5" }
bytes = "1.0"
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
http = "1.0.0"
@ -62,7 +62,7 @@ tower-service = "0.3"
# optional dependencies
axum-macros = { path = "../axum-macros", version = "0.4.2", optional = true }
base64 = { version = "0.21.0", optional = true }
base64 = { version = "0.22.1", optional = true }
hyper = { version = "1.1.0", optional = true }
hyper-util = { version = "0.1.3", features = ["tokio", "server", "service"], optional = true }
multer = { version = "3.0.0", optional = true }
@ -71,7 +71,7 @@ serde_path_to_error = { version = "0.1.8", optional = true }
serde_urlencoded = { version = "0.7", optional = true }
sha1 = { version = "0.10", optional = true }
tokio = { package = "tokio", version = "1.25.0", features = ["time"], optional = true }
tokio-tungstenite = { version = "0.23", optional = true }
tokio-tungstenite = { version = "0.24.0", optional = true }
tracing = { version = "0.1", default-features = false, optional = true }
[dependencies.tower-http]
@ -120,7 +120,7 @@ serde_json = "1.0"
time = { version = "0.3", features = ["serde-human-readable"] }
tokio = { package = "tokio", version = "1.25.0", features = ["macros", "rt", "rt-multi-thread", "net", "test-util"] }
tokio-stream = "0.1"
tokio-tungstenite = "0.23"
tokio-tungstenite = "0.24.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["json"] }
uuid = { version = "1.0", features = ["serde", "v4"] }

View file

@ -1,12 +1,5 @@
Error handling model and utilities
# Table of contents
- [axum's error handling model](#axums-error-handling-model)
- [Routing to fallible services](#routing-to-fallible-services)
- [Applying fallible middleware](#applying-fallible-middleware)
- [Running extractors for error handling](#running-extractors-for-error-handling)
# axum's error handling model
axum is based on [`tower::Service`] which bundles errors through its associated

View file

@ -1,20 +1,5 @@
Types and traits for extracting data from requests.
# Table of contents
- [Intro](#intro)
- [Common extractors](#common-extractors)
- [Applying multiple extractors](#applying-multiple-extractors)
- [The order of extractors](#the-order-of-extractors)
- [Optional extractors](#optional-extractors)
- [Customizing extractor responses](#customizing-extractor-responses)
- [Accessing inner errors](#accessing-inner-errors)
- [Defining custom extractors](#defining-custom-extractors)
- [Accessing other extractors in `FromRequest` or `FromRequestParts` implementations](#accessing-other-extractors-in-fromrequest-or-fromrequestparts-implementations)
- [Request body limits](#request-body-limits)
- [Wrapping extractors](#wrapping-extractors)
- [Logging rejections](#logging-rejections)
# Intro
A handler function is an async function that takes any number of

View file

@ -1,15 +1,3 @@
# Table of contents
- [Intro](#intro)
- [Applying middleware](#applying-middleware)
- [Commonly used middleware](#commonly-used-middleware)
- [Ordering](#ordering)
- [Writing middleware](#writing-middleware)
- [Routing to services/middleware and backpressure](#routing-to-servicesmiddleware-and-backpressure)
- [Accessing state in middleware](#accessing-state-in-middleware)
- [Passing state from middleware to handlers](#passing-state-from-middleware-to-handlers)
- [Rewriting request URI in middleware](#rewriting-request-uri-in-middleware)
# Intro
axum is unique in that it doesn't have its own bespoke middleware system and

View file

@ -1,11 +1,5 @@
Types and traits for generating responses.
# Table of contents
- [Building responses](#building-responses)
- [Returning different response types](#returning-different-response-types)
- [Regarding `impl IntoResponse`](#regarding-impl-intoresponse)
# Building responses
Anything that implements [`IntoResponse`] can be returned from a handler. axum

View file

@ -23,7 +23,11 @@ async fn fallback(uri: Uri) -> (StatusCode, String) {
Fallbacks only apply to routes that aren't matched by anything in the
router. If a handler is matched by a request but returns 404 the
fallback is not called.
fallback is not called. Note that this applies to [`MethodRouter`]s too: if the
request hits a valid path but the [`MethodRouter`] does not have an appropriate
method handler installed, the fallback is not called (use
[`MethodRouter::fallback`] for this purpose instead).
# Handling all requests without other routes

View file

@ -82,6 +82,11 @@ let app = Router::new()
# let _: Router = app;
```
Additionally, while the wildcard route `/foo/*rest` will not match the
paths `/foo` or `/foo/`, a nested router at `/foo` will match the path `/foo`
(but not `/foo/`), and a nested router at `/foo/` will match the path `/foo/`
(but not `/foo`).
# Fallbacks
If a nested router doesn't have its own fallback then it will inherit the

View file

@ -140,7 +140,7 @@ impl<'de> Deserializer<'de> for PathDeserializer<'de> {
where
V: Visitor<'de>,
{
if self.url_params.len() < len {
if self.url_params.len() != len {
return Err(PathDeserializationError::wrong_number_of_parameters()
.got(self.url_params.len())
.expected(len));
@ -160,7 +160,7 @@ impl<'de> Deserializer<'de> for PathDeserializer<'de> {
where
V: Visitor<'de>,
{
if self.url_params.len() < len {
if self.url_params.len() != len {
return Err(PathDeserializationError::wrong_number_of_parameters()
.got(self.url_params.len())
.expected(len));
@ -773,20 +773,6 @@ mod tests {
);
}
#[test]
fn test_parse_tuple_ignoring_additional_fields() {
let url_params = create_url_params(vec![
("a", "abc"),
("b", "true"),
("c", "1"),
("d", "false"),
]);
assert_eq!(
<(&str, bool, u32)>::deserialize(PathDeserializer::new(&url_params)).unwrap(),
("abc", true, 1)
);
}
#[test]
fn test_parse_map() {
let url_params = create_url_params(vec![("a", "1"), ("b", "true"), ("c", "abc")]);
@ -813,6 +799,18 @@ mod tests {
};
}
#[test]
fn test_parse_tuple_too_many_fields() {
test_parse_error!(
vec![("a", "abc"), ("b", "true"), ("c", "1"), ("d", "false"),],
(&str, bool, u32),
ErrorKind::WrongNumberOfParameters {
got: 4,
expected: 3,
}
);
}
#[test]
fn test_wrong_number_of_parameters_error() {
test_parse_error!(

View file

@ -744,6 +744,33 @@ mod tests {
);
}
#[crate::test]
async fn tuple_param_matches_exactly() {
#[allow(dead_code)]
#[derive(Deserialize)]
struct Tuple(String, String);
let app = Router::new()
.route("/foo/:a/:b/:c", get(|_: Path<(String, String)>| async {}))
.route("/bar/:a/:b/:c", get(|_: Path<Tuple>| async {}));
let client = TestClient::new(app);
let res = client.get("/foo/a/b/c").await;
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(
res.text().await,
"Wrong number of path arguments for `Path`. Expected 2 but got 3",
);
let res = client.get("/bar/a/b/c").await;
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(
res.text().await,
"Wrong number of path arguments for `Path`. Expected 2 but got 3",
);
}
#[crate::test]
async fn deserialize_into_vec_of_tuples() {
let app = Router::new().route(

View file

@ -1,22 +1,5 @@
//! axum is a web application framework that focuses on ergonomics and modularity.
//!
//! # Table of contents
//!
//! - [High-level features](#high-level-features)
//! - [Compatibility](#compatibility)
//! - [Example](#example)
//! - [Routing](#routing)
//! - [Handlers](#handlers)
//! - [Extractors](#extractors)
//! - [Responses](#responses)
//! - [Error handling](#error-handling)
//! - [Middleware](#middleware)
//! - [Sharing state with handlers](#sharing-state-with-handlers)
//! - [Building integrations for axum](#building-integrations-for-axum)
//! - [Required dependencies](#required-dependencies)
//! - [Examples](#examples)
//! - [Feature flags](#feature-flags)
//!
//! # High-level features
//!
//! - Route requests to handlers with a macro-free API.

View file

@ -966,7 +966,7 @@ async fn logging_rejections() {
rejection_type: String,
}
let events = capture_tracing::<RejectionEvent, _, _>(|| async {
let events = capture_tracing::<RejectionEvent, _>(|| async {
let app = Router::new()
.route("/extension", get(|_: Extension<Infallible>| async {}))
.route("/string", post(|_: String| async {}));
@ -987,6 +987,7 @@ async fn logging_rejections() {
StatusCode::BAD_REQUEST,
);
})
.with_filter("axum::rejection=trace")
.await;
assert_eq!(

View file

@ -213,61 +213,8 @@ where
type IntoFuture = private::ServeFuture;
fn into_future(self) -> Self::IntoFuture {
private::ServeFuture(Box::pin(async move {
let Self {
tcp_listener,
mut make_service,
tcp_nodelay,
_marker: _,
} = self;
loop {
let (tcp_stream, remote_addr) = match tcp_accept(&tcp_listener).await {
Some(conn) => conn,
None => continue,
};
if let Some(nodelay) = tcp_nodelay {
if let Err(err) = tcp_stream.set_nodelay(nodelay) {
trace!("failed to set TCP_NODELAY on incoming connection: {err:#}");
}
}
let tcp_stream = TokioIo::new(tcp_stream);
poll_fn(|cx| make_service.poll_ready(cx))
.await
.unwrap_or_else(|err| match err {});
let tower_service = make_service
.call(IncomingStream {
tcp_stream: &tcp_stream,
remote_addr,
})
.await
.unwrap_or_else(|err| match err {})
.map_request(|req: Request<Incoming>| req.map(Body::new));
let hyper_service = TowerToHyperService::new(tower_service);
tokio::spawn(async move {
match Builder::new(TokioExecutor::new())
// upgrades needed for websockets
.serve_connection_with_upgrades(tcp_stream, hyper_service)
.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.
}
}
});
}
}))
self.with_graceful_shutdown(std::future::pending())
.into_future()
}
}

View file

@ -1,7 +1,14 @@
use crate::util::AxumMutex;
use std::{future::Future, io, sync::Arc};
use std::{
future::{Future, IntoFuture},
io,
marker::PhantomData,
pin::Pin,
sync::Arc,
};
use serde::{de::DeserializeOwned, Deserialize};
use tracing::instrument::WithSubscriber;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{filter::Targets, fmt::MakeWriter};
@ -14,36 +21,69 @@ pub(crate) struct TracingEvent<T> {
}
/// Run an async closure and capture the tracing output it produces.
pub(crate) async fn capture_tracing<T, F, Fut>(f: F) -> Vec<TracingEvent<T>>
pub(crate) fn capture_tracing<T, F>(f: F) -> CaptureTracing<T, F>
where
F: Fn() -> Fut,
Fut: Future,
T: DeserializeOwned,
{
let (make_writer, handle) = TestMakeWriter::new();
CaptureTracing {
f,
filter: None,
_phantom: PhantomData,
}
}
let subscriber = tracing_subscriber::registry().with(
tracing_subscriber::fmt::layer()
.with_writer(make_writer)
.with_target(true)
.without_time()
.with_ansi(false)
.json()
.flatten_event(false)
.with_filter("axum=trace".parse::<Targets>().unwrap()),
);
pub(crate) struct CaptureTracing<T, F> {
f: F,
filter: Option<Targets>,
_phantom: PhantomData<fn() -> T>,
}
let guard = tracing::subscriber::set_default(subscriber);
impl<T, F> CaptureTracing<T, F> {
pub(crate) fn with_filter(mut self, filter_string: &str) -> Self {
self.filter = Some(filter_string.parse().unwrap());
self
}
}
f().await;
impl<T, F, Fut> IntoFuture for CaptureTracing<T, F>
where
F: Fn() -> Fut + Send + Sync + 'static,
Fut: Future + Send,
T: DeserializeOwned,
{
type Output = Vec<TracingEvent<T>>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
drop(guard);
fn into_future(self) -> Self::IntoFuture {
let Self { f, filter, .. } = self;
Box::pin(async move {
let (make_writer, handle) = TestMakeWriter::new();
handle
.take()
.lines()
.map(|line| serde_json::from_str(line).unwrap())
.collect()
let filter = filter.unwrap_or_else(|| "axum=trace".parse().unwrap());
let subscriber = tracing_subscriber::registry().with(
tracing_subscriber::fmt::layer()
.with_writer(make_writer)
.with_target(true)
.without_time()
.with_ansi(false)
.json()
.flatten_event(false)
.with_filter(filter),
);
let guard = tracing::subscriber::set_default(subscriber);
f().with_current_subscriber().await;
drop(guard);
handle
.take()
.lines()
.map(|line| serde_json::from_str(line).unwrap())
.collect()
})
}
}
struct TestMakeWriter {

View file

@ -8,6 +8,5 @@ publish = false
axum = { path = "../../axum", features = ["ws"] }
futures = "0.3"
tokio = { version = "1", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -6,17 +6,16 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
axum-extra = { path = "../../axum-extra", features = ["typed-header"] }
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["compression-full", "decompression-full"] }
tower = "0.5.1"
tower-http = { version = "0.6.1", features = ["compression-full", "decompression-full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[dev-dependencies]
assert-json-diff = "2.0"
brotli = "3.4"
brotli = "6.0"
flate2 = "1"
http = "1"
zstd = "0.13"

View file

@ -7,9 +7,6 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
http-body-util = "0.1.0"
hyper = "1.0.0"
tokio = { version = "1.0", features = ["full"] }
tower = "0.4"
tower-http = { version = "0.5.0", features = ["map-request-body", "util"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -7,4 +7,4 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.5.0", features = ["cors"] }
tower-http = { version = "0.6.1", features = ["cors"] }

View file

@ -7,7 +7,6 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -8,9 +8,8 @@ publish = false
axum = { path = "../../axum", features = ["macros"] }
bb8 = "0.8"
diesel = "2"
diesel-async = { version = "0.3", features = ["postgres", "bb8"] }
diesel-async = { version = "0.5", features = ["postgres", "bb8"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -6,11 +6,10 @@ publish = false
[dependencies]
axum = { path = "../../axum", features = ["macros"] }
deadpool-diesel = { version = "0.4.1", features = ["postgres"] }
deadpool-diesel = { version = "0.6.1", features = ["postgres"] }
diesel = { version = "2", features = ["postgres"] }
diesel_migrations = "2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -8,6 +8,6 @@ publish = false
axum = { path = "../../axum", features = ["macros"] }
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.5", features = ["trace"] }
tower-http = { version = "0.6.1", features = ["trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -7,6 +7,5 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -6,10 +6,6 @@ publish = false
[dependencies]
axum = { path = "../../axum", features = ["tracing"] }
hyper = { version = "1.0", features = [] }
hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tower-http = { version = "0.5", features = ["timeout", "trace"] }
tracing = "0.1"
tower-http = { version = "0.6.1", features = ["timeout", "trace"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -11,4 +11,4 @@ tokio = { version = "1.0", features = ["full"] }
[dev-dependencies]
http-body-util = "0.1.0"
hyper = { version = "1.0.0", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tower = { version = "0.5.1", features = ["util"] }

View file

@ -9,6 +9,6 @@ axum = { path = "../../axum" }
hyper = { version = "1", features = ["full"] }
hyper-util = "0.1.1"
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["make"] }
tower = { version = "0.5.1", features = ["make", "util"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -7,7 +7,7 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
axum-extra = { path = "../../axum-extra", features = ["typed-header"] }
jsonwebtoken = "8.0"
jsonwebtoken = "9.3"
once_cell = "1.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View file

@ -7,14 +7,13 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util", "timeout", "load-shed", "limit"] }
tower-http = { version = "0.5.0", features = [
tower = { version = "0.5.1", features = ["util", "timeout", "load-shed", "limit"] }
tower-http = { version = "0.6.1", features = [
"add-extension",
"auth",
"compression-full",
"limit",
"trace",
] }
tower-layer = "0.3.2"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -1,5 +1,5 @@
[package]
name = "listen-multiple-addrs"
name = "example-listen-multiple-addrs"
version = "0.1.0"
edition = "2021"
publish = false
@ -9,4 +9,4 @@ axum = { path = "../../axum" }
hyper = { version = "1.0.0", features = ["full"] }
hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] }
tokio = { version = "1", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tower = { version = "0.5.1", features = ["util"] }

View file

@ -12,6 +12,6 @@ hyper-util = { version = "0.1" }
openssl = "0.10"
tokio = { version = "1", features = ["full"] }
tokio-openssl = "0.6"
tower = { version = "0.4", features = ["make"] }
tower = { version = "0.5.1", features = ["make"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -12,7 +12,6 @@ hyper-util = { version = "0.1" }
rustls-pemfile = "1.0.4"
tokio = { version = "1", features = ["full"] }
tokio-rustls = "0.24.1"
tower = { version = "0.4", features = ["make"] }
tower-service = "0.3.2"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -7,6 +7,6 @@ publish = false
[dependencies]
axum = { path = "../../axum", features = ["multipart"] }
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.5.0", features = ["limit", "trace"] }
tower-http = { version = "0.6.1", features = ["limit", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -7,8 +7,6 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
http-body-util = "0.1.0"
hyper = { version = "1.0.0", features = ["full"] }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util", "filter"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -6,8 +6,8 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
metrics = { version = "0.22", default-features = false }
metrics-exporter-prometheus = { version = "0.13", default-features = false }
metrics = { version = "0.23", default-features = false }
metrics-exporter-prometheus = { version = "0.15", default-features = false }
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -7,7 +7,6 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
http-body-util = "0.1.0"
hyper = "1.0.0"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tower = { version = "0.5.1", features = ["util"] }

View file

@ -7,7 +7,6 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.68"
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -0,0 +1,13 @@
[package]
name = "example-request-id"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
axum = { path = "../../axum" }
tokio = { version = "1.0", features = ["full"] }
tower = "0.5"
tower-http = { version = "0.5", features = ["request-id", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -0,0 +1,81 @@
//! Run with
//!
//! ```not_rust
//! cargo run -p example-request-id
//! ```
use axum::{
http::{HeaderName, Request},
response::Html,
routing::get,
Router,
};
use tower::ServiceBuilder;
use tower_http::{
request_id::{MakeRequestUuid, PropagateRequestIdLayer, SetRequestIdLayer},
trace::TraceLayer,
};
use tracing::{error, info, info_span};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
const REQUEST_ID_HEADER: &str = "x-request-id";
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
// axum logs rejections from built-in extractors with the `axum::rejection`
// target, at `TRACE` level. `axum::rejection=trace` enables showing those events
format!(
"{}=debug,tower_http=debug,axum::rejection=trace",
env!("CARGO_CRATE_NAME")
)
.into()
}),
)
.with(tracing_subscriber::fmt::layer())
.init();
let x_request_id = HeaderName::from_static(REQUEST_ID_HEADER);
let middleware = ServiceBuilder::new()
.layer(SetRequestIdLayer::new(
x_request_id.clone(),
MakeRequestUuid,
))
.layer(
TraceLayer::new_for_http().make_span_with(|request: &Request<_>| {
// Log the request id as generated.
let request_id = request.headers().get(REQUEST_ID_HEADER);
match request_id {
Some(request_id) => info_span!(
"http_request",
request_id = ?request_id,
),
None => {
error!("could not extract request_id");
info_span!("http_request")
}
}
}),
)
// send headers from request to response headers
.layer(PropagateRequestIdLayer::new(x_request_id));
// build our application with a route
let app = Router::new().route("/", get(handler)).layer(middleware);
// run it
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> {
info!("Hello world!");
Html("<h1>Hello, World!</h1>")
}

View file

@ -9,6 +9,6 @@ axum = { path = "../../axum" }
reqwest = { version = "0.12", features = ["stream"] }
tokio = { version = "1.0", features = ["full"] }
tokio-stream = "0.1"
tower-http = { version = "0.5.0", features = ["trace"] }
tower-http = { version = "0.6.1", features = ["trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -8,13 +8,13 @@ publish = false
axum = { path = "../../axum" }
futures = "0.3"
hyper = { version = "1.0.0", features = ["full"] }
prost = "0.11"
tokio = { version = "1", features = ["full"] }
tonic = { version = "0.9" }
tonic-reflection = "0.9"
tower = { version = "0.4", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
#prost = "0.11"
#tokio = { version = "1", features = ["full"] }
#tonic = { version = "0.9" }
#tonic-reflection = "0.9"
tower = { version = "0.5.1", features = ["full"] }
#tracing = "0.1"
#tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[build-dependencies]
tonic-build = { version = "0.9", features = ["prost"] }

View file

@ -9,4 +9,4 @@ axum = { path = "../../axum" }
hyper = { version = "1.0", features = [] }
hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tower = { version = "0.5.1", features = ["util"] }

View file

@ -14,3 +14,6 @@ axum-extra = { path = "../../axum-extra", default-features = false }
futures-executor = "0.3.21"
http = "1.0.0"
tower-service = "0.3.1"
[package.metadata.cargo-machete]
ignored = ["axum-extra"]

View file

@ -10,4 +10,4 @@ tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "any", "postgres"] }
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "any", "postgres"] }

View file

@ -11,11 +11,11 @@ futures = "0.3"
headers = "0.4"
tokio = { version = "1.0", features = ["full"] }
tokio-stream = "0.1"
tower-http = { version = "0.5.0", features = ["fs", "trace"] }
tower-http = { version = "0.6.1", features = ["fs", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[dev-dependencies]
eventsource-stream = "0.2"
reqwest = { version = "0.12", features = ["stream"] }
reqwest-eventsource = "0.5"
reqwest-eventsource = "0.6"

View file

@ -6,9 +6,8 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
axum-extra = { path = "../../axum-extra" }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tower-http = { version = "0.5.0", features = ["fs", "trace"] }
tower = { version = "0.5.1", features = ["util"] }
tower-http = { version = "0.6.1", features = ["fs", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

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

View file

@ -5,7 +5,7 @@ edition = "2021"
publish = false
[dependencies]
askama = "0.11"
askama = "0.12"
axum = { path = "../../axum" }
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"

View file

@ -7,6 +7,5 @@ publish = false
[dependencies]
axum = { path = "../../axum", features = ["ws"] }
futures = "0.3"
hyper = { version = "1.0.0", features = ["full"] }
tokio = { version = "1.0", features = ["full"] }
tokio-tungstenite = "0.23"
tokio-tungstenite = "0.24"

View file

@ -7,14 +7,13 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
http-body-util = "0.1.0"
hyper = { version = "1.0.0", features = ["full"] }
hyper-util = { version = "0.1", features = ["client", "http1", "client-legacy"] }
mime = "0.3"
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.5.0", features = ["trace"] }
tower-http = { version = "0.6.1", features = ["trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[dev-dependencies]
tower = { version = "0.4", features = ["util"] }
tower = { version = "0.5.1", features = ["util"] }

View file

@ -6,8 +6,7 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
axum-server = { version = "0.6", features = ["tls-rustls"] }
hyper = { version = "0.14", features = ["full"] }
axum-server = { version = "0.7", features = ["tls-rustls"] }
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -6,7 +6,7 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
axum-server = { version = "0.6", features = ["tls-rustls"] }
axum-server = { version = "0.7", features = ["tls-rustls"] }
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -8,8 +8,8 @@ publish = false
axum = { path = "../../axum" }
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util", "timeout"] }
tower-http = { version = "0.5.0", features = ["add-extension", "trace"] }
tower = { version = "0.5.1", features = ["util", "timeout"] }
tower-http = { version = "0.6.1", features = ["add-extension", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
uuid = { version = "1.0", features = ["serde", "v4"] }

View file

@ -6,8 +6,8 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
bb8 = "0.7.1"
bb8-postgres = "0.7.0"
bb8 = "0.8.5"
bb8-postgres = "0.8.1"
tokio = { version = "1.0", features = ["full"] }
tokio-postgres = "0.7.2"
tracing = "0.1"

View file

@ -6,9 +6,9 @@ publish = false
[dependencies]
axum = { path = "../../axum" }
bb8 = "0.7.1"
bb8-redis = "0.14.0"
redis = "0.24.0"
bb8 = "0.8.5"
bb8-redis = "0.17.0"
redis = "0.27.2"
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -7,6 +7,6 @@ publish = false
[dependencies]
axum = { path = "../../axum", features = ["tracing"] }
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.5.0", features = ["trace"] }
tower-http = { version = "0.6.1", features = ["trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -10,6 +10,5 @@ http-body-util = "0.1"
hyper = { version = "1.0.0", features = ["full"] }
hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] }
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util"] }
tracing = "0.1"
tower = { version = "0.5.1", features = ["util"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View file

@ -6,10 +6,9 @@ version = "0.1.0"
[dependencies]
axum = { path = "../../axum" }
http-body = "1.0.0"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0.29"
tokio = { version = "1.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
validator = { version = "0.14.0", features = ["derive"] }
validator = { version = "0.18.1", features = ["derive"] }

View file

@ -11,9 +11,8 @@ futures = "0.3"
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
headers = "0.4"
tokio = { version = "1.0", features = ["full"] }
tokio-tungstenite = "0.23"
tower = { version = "0.4", features = ["util"] }
tower-http = { version = "0.5.0", features = ["fs", "trace"] }
tokio-tungstenite = "0.24.0"
tower-http = { version = "0.6.1", features = ["fs", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }