mirror of
https://github.com/tokio-rs/axum.git
synced 2025-01-11 12:31:25 +01:00
axum 0.6 and friends 🎉 (#1570)
* changelog * bump versions * reorder changelogs a bit * Apply suggestions from code review Co-authored-by: Jonas Platte <jplatte+git@posteo.de> * Expand fallback inheritance * Reword tsr * Mention `parse-body-based-on-content-type` example Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
This commit is contained in:
parent
0b26411f39
commit
1b6780cf6c
10 changed files with 541 additions and 21 deletions
|
@ -9,6 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None.
|
||||
|
||||
# 0.3.0 (25. November, 2022)
|
||||
|
||||
- **added:** Added new `FromRequestParts` trait. See axum's changelog for more
|
||||
details ([#1272])
|
||||
- **breaking:** `FromRequest` has been reworked and `RequestParts` has been
|
||||
removed. See axum's changelog for more details ([#1272])
|
||||
- **breaking:** `BodyAlreadyExtracted` has been removed ([#1272])
|
||||
- **breaking:** `AppendHeaders` now works on any `impl IntoIterator` ([#1495])
|
||||
|
||||
[#1272]: https://github.com/tokio-rs/axum/pull/1272
|
||||
[#1495]: https://github.com/tokio-rs/axum/pull/1495
|
||||
|
||||
<details>
|
||||
<summary>0.3.0 Pre-Releases</summary>
|
||||
|
||||
# 0.3.0-rc.3 (8. November, 2022)
|
||||
|
||||
- **added:** Add `DefaultBodyLimit::max` for changing the default body limit ([#1397])
|
||||
|
@ -47,6 +62,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#1155]: https://github.com/tokio-rs/axum/pull/1155
|
||||
[#1272]: https://github.com/tokio-rs/axum/pull/1272
|
||||
|
||||
</details>
|
||||
|
||||
# 0.2.8 (10. September, 2022)
|
||||
|
||||
- **breaking:** Added default limit to how much data `Bytes::from_request` will
|
||||
|
|
|
@ -9,7 +9,7 @@ license = "MIT"
|
|||
name = "axum-core"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/tokio-rs/axum"
|
||||
version = "0.3.0-rc.3" # remember to also bump the version that axum depends on
|
||||
version = "0.3.0" # remember to also bump the version that axum depends on
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
|
@ -25,7 +25,7 @@ tower-service = "0.3"
|
|||
rustversion = "1.0.9"
|
||||
|
||||
[dev-dependencies]
|
||||
axum = { path = "../axum", version = "0.6.0-rc.2" }
|
||||
axum = { path = "../axum", version = "0.6.0" }
|
||||
futures-util = "0.3"
|
||||
hyper = "0.14"
|
||||
tokio = { version = "1.0", features = ["macros"] }
|
||||
|
|
|
@ -66,8 +66,8 @@ use tower_layer::Layer;
|
|||
///
|
||||
/// [`Body::data`]: http_body::Body::data
|
||||
/// [`Bytes`]: bytes::Bytes
|
||||
/// [`Json`]: https://docs.rs/axum/0.6.0-rc.2/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.6.0-rc.2/axum/struct.Form.html
|
||||
/// [`Json`]: https://docs.rs/axum/0.6.0/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.6.0/axum/struct.Form.html
|
||||
/// [`FromRequest`]: crate::extract::FromRequest
|
||||
/// [`RequestBodyLimit`]: https://docs.rs/tower-http/latest/tower_http/limit/struct.RequestBodyLimit.html
|
||||
/// [`RequestExt::with_limited_body`]: crate::RequestExt::with_limited_body
|
||||
|
@ -114,8 +114,8 @@ impl DefaultBodyLimit {
|
|||
///
|
||||
/// [`tower_http::limit`]: https://docs.rs/tower-http/0.3.4/tower_http/limit/index.html
|
||||
/// [`Bytes`]: bytes::Bytes
|
||||
/// [`Json`]: https://docs.rs/axum/0.6.0-rc.2/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.6.0-rc.2/axum/struct.Form.html
|
||||
/// [`Json`]: https://docs.rs/axum/0.6.0/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.6.0/axum/struct.Form.html
|
||||
pub fn disable() -> Self {
|
||||
Self {
|
||||
kind: DefaultBodyLimitKind::Disable,
|
||||
|
@ -147,8 +147,8 @@ impl DefaultBodyLimit {
|
|||
/// ```
|
||||
///
|
||||
/// [`Bytes::from_request`]: bytes::Bytes
|
||||
/// [`Json`]: https://docs.rs/axum/0.6.0-rc.2/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.6.0-rc.2/axum/struct.Form.html
|
||||
/// [`Json`]: https://docs.rs/axum/0.6.0/axum/struct.Json.html
|
||||
/// [`Form`]: https://docs.rs/axum/0.6.0/axum/struct.Form.html
|
||||
pub fn max(limit: usize) -> Self {
|
||||
Self {
|
||||
kind: DefaultBodyLimitKind::Limit(limit),
|
||||
|
|
|
@ -37,7 +37,7 @@ mod private {
|
|||
///
|
||||
/// See [`axum::extract`] for more general docs about extraxtors.
|
||||
///
|
||||
/// [`axum::extract`]: https://docs.rs/axum/0.6.0-rc.2/axum/extract/index.html
|
||||
/// [`axum::extract`]: https://docs.rs/axum/0.6.0/axum/extract/index.html
|
||||
#[async_trait]
|
||||
#[cfg_attr(
|
||||
nightly_error_messages,
|
||||
|
@ -106,7 +106,7 @@ pub trait FromRequestParts<S>: Sized {
|
|||
/// This ensures your extractor is as flexible as possible.
|
||||
///
|
||||
/// [`http::Request<B>`]: http::Request
|
||||
/// [`axum::extract`]: https://docs.rs/axum/0.6.0-rc.2/axum/extract/index.html
|
||||
/// [`axum::extract`]: https://docs.rs/axum/0.6.0/axum/extract/index.html
|
||||
#[async_trait]
|
||||
#[cfg_attr(
|
||||
nightly_error_messages,
|
||||
|
|
|
@ -9,6 +9,45 @@ and this project adheres to [Semantic Versioning].
|
|||
|
||||
- None.
|
||||
|
||||
# 0.4.0 (25. November, 2022)
|
||||
|
||||
- **added:** Add `RouterExt::route_with_tsr` for adding routes with an
|
||||
additional "trailing slash redirect" route ([#1119])
|
||||
- **added:** Support chaining handlers with `HandlerCallWithExtractors::or` ([#1170])
|
||||
- **added:** Add Protocol Buffer extractor and response ([#1239])
|
||||
- **added:** Add `Either*` types for combining extractors and responses into a
|
||||
single type ([#1263])
|
||||
- **added:** `WithRejection` extractor for customizing other extractors' rejections ([#1262])
|
||||
- **added:** Add sync constructors to `CookieJar`, `PrivateCookieJar`, and
|
||||
`SignedCookieJar` so they're easier to use in custom middleware
|
||||
- **changed:** For methods that accept some `S: Service`, the bounds have been
|
||||
relaxed so the return type can be any type that implements `IntoResponse` rather than being a
|
||||
literal `Response`
|
||||
- **change:** axum-extra's MSRV is now 1.60 ([#1239])
|
||||
- **breaking:** `Form` has a new rejection type ([#1496])
|
||||
- **breaking:** `Query` has a new rejection type ([#1496])
|
||||
- **breaking:** `Resource::nest` and `Resource::nest_collection` have been
|
||||
removed. You can instead convert the `Resource` into a `Router` and
|
||||
add additional routes as necessary ([#1086])
|
||||
- **breaking:** `SignedCookieJar` and `PrivateCookieJar` now extracts the keys
|
||||
from the router's state, rather than extensions
|
||||
- **breaking:** `Resource` has a new `S` type param which represents the state ([#1155])
|
||||
- **breaking:** `RouterExt::route_with_tsr` now only accepts `MethodRouter`s ([#1155])
|
||||
- **added:** `RouterExt::route_service_with_tsr` for routing to any `Service` ([#1155])
|
||||
|
||||
[#1086]: https://github.com/tokio-rs/axum/pull/1086
|
||||
[#1119]: https://github.com/tokio-rs/axum/pull/1119
|
||||
[#1155]: https://github.com/tokio-rs/axum/pull/1155
|
||||
[#1170]: https://github.com/tokio-rs/axum/pull/1170
|
||||
[#1214]: https://github.com/tokio-rs/axum/pull/1214
|
||||
[#1239]: https://github.com/tokio-rs/axum/pull/1239
|
||||
[#1262]: https://github.com/tokio-rs/axum/pull/1262
|
||||
[#1263]: https://github.com/tokio-rs/axum/pull/1263
|
||||
[#1496]: https://github.com/tokio-rs/axum/pull/1496
|
||||
|
||||
<details>
|
||||
<summary>0.4.0 Pre-Releases</summary>
|
||||
|
||||
# 0.4.0-rc.3 (19. November, 2022)
|
||||
|
||||
- **breaking:** Depend axum 0.6.0-rc.5 and axum-macros 0.3.0-rc.3
|
||||
|
@ -53,6 +92,8 @@ and this project adheres to [Semantic Versioning].
|
|||
[#1262]: https://github.com/tokio-rs/axum/pull/1262
|
||||
[#1263]: https://github.com/tokio-rs/axum/pull/1263
|
||||
|
||||
</details>
|
||||
|
||||
# 0.3.7 (09. August, 2022)
|
||||
|
||||
- **fixed:** Depend on axum 0.5.15 which contains a fix for an accidental breaking change.
|
||||
|
|
|
@ -9,7 +9,7 @@ license = "MIT"
|
|||
name = "axum-extra"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/tokio-rs/axum"
|
||||
version = "0.4.0-rc.3"
|
||||
version = "0.4.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
@ -35,7 +35,7 @@ spa = ["tower-http/fs"]
|
|||
typed-routing = ["dep:axum-macros", "dep:serde", "dep:percent-encoding"]
|
||||
|
||||
[dependencies]
|
||||
axum = { path = "../axum", version = "=0.6.0-rc.5", default-features = false }
|
||||
axum = { path = "../axum", version = "0.6.0", default-features = false }
|
||||
bytes = "1.1.0"
|
||||
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
|
||||
http = "0.2"
|
||||
|
@ -48,7 +48,7 @@ tower-layer = "0.3"
|
|||
tower-service = "0.3"
|
||||
|
||||
# optional dependencies
|
||||
axum-macros = { path = "../axum-macros", version = "=0.3.0-rc.3", optional = true }
|
||||
axum-macros = { path = "../axum-macros", version = "0.3.0", optional = true }
|
||||
cookie = { package = "cookie", version = "0.16", features = ["percent-encode"], optional = true }
|
||||
percent-encoding = { version = "2.1", optional = true }
|
||||
prost = { version = "0.11", optional = true }
|
||||
|
@ -59,7 +59,7 @@ tokio-stream = { version = "0.1.9", optional = true }
|
|||
tokio-util = { version = "0.7", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
axum = { path = "../axum", version = "=0.6.0-rc.5", features = ["headers"] }
|
||||
axum = { path = "../axum", version = "0.6.0", features = ["headers"] }
|
||||
futures = "0.3"
|
||||
hyper = "0.14"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["json", "stream", "multipart"] }
|
||||
|
|
|
@ -9,6 +9,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- None.
|
||||
|
||||
# 0.3.0 (25. November, 2022)
|
||||
|
||||
- **added:** Add `#[derive(FromRequestParts)]` for deriving an implementation of
|
||||
`FromRequestParts`, similarly to `#[derive(FromRequest)]` ([#1305])
|
||||
- **added:** Add `#[derive(FromRef)]` ([#1430])
|
||||
- **added:** Add `#[from_ref(skip)]` to skip implementing `FromRef` for individual fields ([#1537])
|
||||
- **added:** Support using a different rejection for `#[derive(FromRequest)]`
|
||||
with `#[from_request(rejection(MyRejection))]` ([#1256])
|
||||
- **change:** axum-macro's MSRV is now 1.60 ([#1239])
|
||||
- **breaking:** `#[derive(FromRequest)]` will no longer generate a rejection
|
||||
enum but instead generate `type Rejection = axum::response::Response`. Use the
|
||||
new `#[from_request(rejection(MyRejection))]` attribute to change this.
|
||||
The `rejection_derive` attribute has also been removed ([#1272])
|
||||
|
||||
[#1239]: https://github.com/tokio-rs/axum/pull/1239
|
||||
[#1256]: https://github.com/tokio-rs/axum/pull/1256
|
||||
[#1272]: https://github.com/tokio-rs/axum/pull/1272
|
||||
[#1305]: https://github.com/tokio-rs/axum/pull/1305
|
||||
[#1430]: https://github.com/tokio-rs/axum/pull/1430
|
||||
[#1537]: https://github.com/tokio-rs/axum/pull/1537
|
||||
|
||||
<details>
|
||||
<summary>0.3.0 Pre-Releases</summary>
|
||||
|
||||
# 0.3.0-rc.3 (18. November, 2022)
|
||||
|
||||
- **added:** Add `#[from_ref(skip)]` to skip implementing `FromRef` for individual fields ([#1537])
|
||||
|
@ -38,6 +62,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#1272]: https://github.com/tokio-rs/axum/pull/1272
|
||||
[#1305]: https://github.com/tokio-rs/axum/pull/1305
|
||||
|
||||
</details>
|
||||
|
||||
# 0.2.3 (27. June, 2022)
|
||||
|
||||
- **change:** axum-macros's MSRV is now 1.56 ([#1098])
|
||||
|
|
|
@ -9,7 +9,7 @@ license = "MIT"
|
|||
name = "axum-macros"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/tokio-rs/axum"
|
||||
version = "0.3.0-rc.3" # remember to also bump the version that axum and axum-extra depends on
|
||||
version = "0.3.0" # remember to also bump the version that axum and axum-extra depends on
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
@ -25,8 +25,8 @@ syn = { version = "1.0", features = [
|
|||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
axum = { path = "../axum", version = "=0.6.0-rc.5", features = ["headers", "macros"] }
|
||||
axum-extra = { path = "../axum-extra", version = "=0.4.0-rc.3", features = ["typed-routing", "cookie-private"] }
|
||||
axum = { path = "../axum", version = "0.6.0", features = ["headers", "macros"] }
|
||||
axum-extra = { path = "../axum-extra", version = "0.4.0", features = ["typed-routing", "cookie-private"] }
|
||||
rustversion = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
|
|
@ -7,11 +7,445 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
# Unreleased
|
||||
|
||||
- None.
|
||||
|
||||
# 0.6.0 (25. November, 2022)
|
||||
|
||||
## Routing
|
||||
|
||||
- **fixed:** Nested routers are now allowed to have fallbacks ([#1521]):
|
||||
|
||||
```rust
|
||||
let api_router = Router::new()
|
||||
.route("/users", get(|| { ... }))
|
||||
.fallback(api_fallback);
|
||||
|
||||
let app = Router::new()
|
||||
// this would panic in 0.5 but in 0.6 it just works
|
||||
//
|
||||
// requests starting with `/api` but not handled by `api_router`
|
||||
// will go to `/api_fallback`
|
||||
.nest("/api", api_router);
|
||||
```
|
||||
|
||||
The outer router's fallback will still apply if a nested router doesn't have
|
||||
its own fallback:
|
||||
|
||||
```rust
|
||||
// this time without a fallback
|
||||
let api_router = Router::new().route("/users", get(|| { ... }));
|
||||
|
||||
let app = Router::new()
|
||||
.nest("/api", api_router)
|
||||
// `api_fallback` will inherit this fallback
|
||||
.fallback(app_fallback);
|
||||
```
|
||||
|
||||
- **breaking:** The request `/foo/` no longer matches `/foo/*rest`. If you want
|
||||
to match `/foo/` you have to add a route specifically for that ([#1086])
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use axum::{Router, routing::get, extract::Path};
|
||||
|
||||
let app = Router::new()
|
||||
// this will match `/foo/bar/baz`
|
||||
.route("/foo/*rest", get(handler))
|
||||
// this will match `/foo/`
|
||||
.route("/foo/", get(handler))
|
||||
// if you want `/foo` to match you must also add an explicit route for it
|
||||
.route("/foo", get(handler));
|
||||
|
||||
async fn handler(
|
||||
// use an `Option` because `/foo/` and `/foo` don't have any path params
|
||||
params: Option<Path<String>>,
|
||||
) {}
|
||||
```
|
||||
|
||||
- **breaking:** Path params for wildcard routes no longer include the prefix
|
||||
`/`. e.g. `/foo.js` will match `/*filepath` with a value of `foo.js`, _not_
|
||||
`/foo.js` ([#1086])
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use axum::{Router, routing::get, extract::Path};
|
||||
|
||||
let app = Router::new().route("/foo/*rest", get(handler));
|
||||
|
||||
async fn handler(
|
||||
Path(params): Path<String>,
|
||||
) {
|
||||
// for the request `/foo/bar/baz` the value of `params` will be `bar/baz`
|
||||
//
|
||||
// on 0.5 it would be `/bar/baz`
|
||||
}
|
||||
```
|
||||
|
||||
- **fixed:** Routes like `/foo` and `/*rest` are no longer considered
|
||||
overlapping. `/foo` will take priority ([#1086])
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use axum::{Router, routing::get};
|
||||
|
||||
let app = Router::new()
|
||||
// this used to not be allowed but now just works
|
||||
.route("/foo/*rest", get(foo))
|
||||
.route("/foo/bar", get(bar));
|
||||
|
||||
async fn foo() {}
|
||||
|
||||
async fn bar() {}
|
||||
```
|
||||
|
||||
- **breaking:** Automatic trailing slash redirects have been removed.
|
||||
Previously if you added a route for `/foo`, axum would redirect calls to
|
||||
`/foo/` to `/foo` (or vice versa for `/foo/`):
|
||||
|
||||
```rust
|
||||
use axum::{Router, routing::get};
|
||||
|
||||
let app = Router::new()
|
||||
// a request to `GET /foo/` will now get `404 Not Found`
|
||||
// whereas in 0.5 axum would redirect to `/foo`
|
||||
//
|
||||
// same goes the other way if you had the route `/foo/`
|
||||
// axum will no longer redirect from `/foo` to `/foo/`
|
||||
.route("/foo", get(handler));
|
||||
|
||||
async fn handler() {}
|
||||
```
|
||||
|
||||
Either explicitly add routes for `/foo` and `/foo/` or use
|
||||
`axum_extra::routing::RouterExt::route_with_tsr` if you want the old behavior
|
||||
([#1119])
|
||||
|
||||
- **breaking:** `Router::fallback` now only accepts `Handler`s (similarly to
|
||||
what `get`, `post`, etc. accept). Use the new `Router::fallback_service` for
|
||||
setting any `Service` as the fallback ([#1155])
|
||||
|
||||
This fallback on 0.5:
|
||||
|
||||
```rust
|
||||
use axum::{Router, handler::Handler};
|
||||
|
||||
let app = Router::new().fallback(fallback.into_service());
|
||||
|
||||
async fn fallback() {}
|
||||
```
|
||||
|
||||
Becomes this in 0.6
|
||||
|
||||
```rust
|
||||
use axum::Router;
|
||||
|
||||
let app = Router::new().fallback(fallback);
|
||||
|
||||
async fn fallback() {}
|
||||
```
|
||||
|
||||
- **changed:** `Router::nest` now only accepts `Router`s, the general-purpose
|
||||
`Service` nesting method has been renamed to `nest_service` ([#1368])
|
||||
- **breaking:** Allow `Error: Into<Infallible>` for `Route::{layer, route_layer}` ([#924])
|
||||
- **breaking:** `MethodRouter` now panics on overlapping routes ([#1102])
|
||||
- **breaking:** `Router::route` now only accepts `MethodRouter`s created with
|
||||
`get`, `post`, etc. Use the new `Router::route_service` for routing to
|
||||
any `Service`s ([#1155])
|
||||
- **breaking:** Adding a `.route_layer` onto a `Router` or `MethodRouter`
|
||||
without any routes will now result in a panic. Previously, this just did
|
||||
nothing. [#1327]
|
||||
- **breaking:** `RouterService` has been removed since `Router` now implements
|
||||
`Service` when the state is `()`. Use `Router::with_state` to provide the
|
||||
state and get a `Router<()>` ([#1552])
|
||||
state and get a `Router<()>`. Note that `RouterService` only existed in the
|
||||
pre-releases, not 0.5 ([#1552])
|
||||
|
||||
## Extractors
|
||||
|
||||
- **added:** Added new type safe `State` extractor. This can be used with
|
||||
`Router::with_state` and gives compile errors for missing states, whereas
|
||||
`Extension` would result in runtime errors ([#1155])
|
||||
|
||||
We recommend migrating from `Extension` to `State` for sharing application state since that is more type
|
||||
safe and faster. That is done by using `Router::with_state` and `State`.
|
||||
|
||||
This setup in 0.5
|
||||
|
||||
```rust
|
||||
use axum::{routing::get, Extension, Router};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/", get(handler))
|
||||
.layer(Extension(AppState {}));
|
||||
|
||||
async fn handler(Extension(app_state): Extension<AppState>) {}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState {}
|
||||
```
|
||||
|
||||
Becomes this in 0.6 using `State`:
|
||||
|
||||
```rust
|
||||
use axum::{routing::get, extract::State, Router};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/", get(handler))
|
||||
.with_state(AppState {});
|
||||
|
||||
async fn handler(State(app_state): State<AppState>) {}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState {}
|
||||
```
|
||||
|
||||
If you have multiple extensions, you can use fields on `AppState` and implement
|
||||
`FromRef`:
|
||||
|
||||
```rust
|
||||
use axum::{extract::{State, FromRef}, routing::get, Router};
|
||||
|
||||
let state = AppState {
|
||||
client: HttpClient {},
|
||||
database: Database {},
|
||||
};
|
||||
|
||||
let app = Router::new().route("/", get(handler)).with_state(state);
|
||||
|
||||
async fn handler(
|
||||
State(client): State<HttpClient>,
|
||||
State(database): State<Database>,
|
||||
) {}
|
||||
|
||||
// the derive requires enabling the "macros" feature
|
||||
#[derive(Clone, FromRef)]
|
||||
struct AppState {
|
||||
client: HttpClient,
|
||||
database: Database,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct HttpClient {}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Database {}
|
||||
```
|
||||
|
||||
- **breaking:** It is now only possible for one extractor per handler to consume
|
||||
the request body. In 0.5 doing so would result in runtime errors but in 0.6 it
|
||||
is a compile error ([#1272])
|
||||
|
||||
axum enforces this by only allowing the _last_ extractor to consume the
|
||||
request.
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use axum::{Json, http::HeaderMap};
|
||||
|
||||
// This wont compile on 0.6 because both `Json` and `String` need to consume
|
||||
// the request body. You can use either `Json` or `String`, but not both.
|
||||
async fn handler_1(
|
||||
json: Json<serde_json::Value>,
|
||||
string: String,
|
||||
) {}
|
||||
|
||||
// This won't work either since `Json` is not the last extractor.
|
||||
async fn handler_2(
|
||||
json: Json<serde_json::Value>,
|
||||
headers: HeaderMap,
|
||||
) {}
|
||||
|
||||
// This works!
|
||||
async fn handler_3(
|
||||
headers: HeaderMap,
|
||||
json: Json<serde_json::Value>,
|
||||
) {}
|
||||
```
|
||||
|
||||
This is done by reworking the `FromRequest` trait and introducing a new
|
||||
`FromRequestParts` trait.
|
||||
|
||||
If your extractor needs to consume the request body then you should implement
|
||||
`FromRequest`, otherwise implement `FromRequestParts`.
|
||||
|
||||
This extractor in 0.5:
|
||||
|
||||
```rust
|
||||
struct MyExtractor { /* ... */ }
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for MyExtractor
|
||||
where
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = StatusCode;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Becomes this in 0.6:
|
||||
|
||||
```rust
|
||||
use axum::{
|
||||
extract::{FromRequest, FromRequestParts},
|
||||
http::{StatusCode, Request, request::Parts},
|
||||
async_trait,
|
||||
};
|
||||
|
||||
struct MyExtractor { /* ... */ }
|
||||
|
||||
// implement `FromRequestParts` if you don't need to consume the request body
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for MyExtractor
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = StatusCode;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// implement `FromRequest` if you do need to consume the request body
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for MyExtractor
|
||||
where
|
||||
S: Send + Sync,
|
||||
B: Send + 'static,
|
||||
{
|
||||
type Rejection = StatusCode;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For an example of how to write an extractor that accepts different
|
||||
`Content-Types` see the [`parse-body-based-on-content-type`] example.
|
||||
|
||||
- **added:** `FromRequest` and `FromRequestParts` derive macro re-exports from
|
||||
[`axum-macros`] behind the `macros` feature ([#1352])
|
||||
- **added:** Add `RequestExt` and `RequestPartsExt` which adds convenience
|
||||
methods for running extractors to `http::Request` and `http::request::Parts` ([#1301])
|
||||
- **added**: `JsonRejection` now displays the path at which a deserialization
|
||||
error occurred ([#1371])
|
||||
- **added:** Add `extract::RawForm` for accessing raw urlencoded query bytes or request body ([#1487])
|
||||
- **fixed:** Used `400 Bad Request` for `FailedToDeserializeQueryString`
|
||||
rejections, instead of `422 Unprocessable Entity` ([#1387])
|
||||
- **changed**: The inner error of a `JsonRejection` is now
|
||||
`serde_path_to_error::Error<serde_json::Error>`. Previously it was
|
||||
`serde_json::Error` ([#1371])
|
||||
- **changed:** The default body limit now applies to the `Multipart` extractor ([#1420])
|
||||
- **breaking:** `ContentLengthLimit` has been removed. Use `DefaultBodyLimit` instead ([#1400])
|
||||
- **breaking:** `RequestParts` has been removed as part of the `FromRequest`
|
||||
rework ([#1272])
|
||||
- **breaking:** `BodyAlreadyExtracted` has been removed ([#1272])
|
||||
- **breaking:** The following types or traits have a new `S` type param
|
||||
which represents the state ([#1155]):
|
||||
- `Router`, defaults to `()`
|
||||
- `MethodRouter`, defaults to `()`
|
||||
- `FromRequest`, no default
|
||||
- `Handler`, no default
|
||||
- **breaking:** `MatchedPath` can now no longer be extracted in middleware for
|
||||
nested routes. In previous versions it returned invalid data when extracted
|
||||
from a middleware applied to a nested router. `MatchedPath` can still be
|
||||
extracted from handlers and middleware that aren't on nested routers ([#1462])
|
||||
- **breaking:** Rename `FormRejection::FailedToDeserializeQueryString` to
|
||||
`FormRejection::FailedToDeserializeForm` ([#1496])
|
||||
|
||||
## Middleware
|
||||
|
||||
- **added:** Support running extractors on `middleware::from_fn` functions ([#1088])
|
||||
- **added**: Add `middleware::from_fn_with_state` to enable running extractors that require
|
||||
state ([#1342])
|
||||
- **added:** Add `middleware::from_extractor_with_state` ([#1396])
|
||||
- **added:** Add `map_request`, `map_request_with_state` for transforming the
|
||||
request with an async function ([#1408])
|
||||
- **added:** Add `map_response`, `map_response_with_state` for transforming the
|
||||
response with an async function ([#1414])
|
||||
- **added:** Support any middleware response that implements `IntoResponse` ([#1152])
|
||||
- **breaking:** Remove `extractor_middleware` which was previously deprecated.
|
||||
Use `axum::middleware::from_extractor` instead ([#1077])
|
||||
- **breaking:** Require middleware added with `Handler::layer` to have
|
||||
`Infallible` as the error type ([#1152])
|
||||
|
||||
## Misc
|
||||
|
||||
- **added:** Support compiling to WASM. See the `simple-router-wasm` example
|
||||
for more details ([#1382])
|
||||
- **added:** Add `ServiceExt` with methods for turning any `Service` into a
|
||||
`MakeService` similarly to `Router::into_make_service` ([#1302])
|
||||
- **added:** String and binary `From` impls have been added to `extract::ws::Message`
|
||||
to be more inline with `tungstenite` ([#1421])
|
||||
- **added:** Add `#[derive(axum::extract::FromRef)]` ([#1430])
|
||||
- **added:** Add `accept_unmasked_frames` setting in WebSocketUpgrade ([#1529])
|
||||
- **added:** Add `WebSocketUpgrade::on_failed_upgrade` to customize what to do
|
||||
when upgrading a connection fails ([#1539])
|
||||
- **fixed:** Annotate panicking functions with `#[track_caller]` so the error
|
||||
message points to where the user added the invalid route, rather than
|
||||
somewhere internally in axum ([#1248])
|
||||
- **changed:** axum's MSRV is now 1.60 ([#1239])
|
||||
- **changed:** For methods that accept some `S: Service`, the bounds have been
|
||||
relaxed so the response type must implement `IntoResponse` rather than being a
|
||||
literal `Response`
|
||||
- **breaking:** New `tokio` default feature needed for WASM support. If you
|
||||
don't need WASM support but have `default_features = false` for other reasons
|
||||
you likely need to re-enable the `tokio` feature ([#1382])
|
||||
- **breaking:** `handler::{WithState, IntoService}` are merged into one type,
|
||||
named `HandlerService` ([#1418])
|
||||
|
||||
[#924]: https://github.com/tokio-rs/axum/pull/924
|
||||
[#1077]: https://github.com/tokio-rs/axum/pull/1077
|
||||
[#1086]: https://github.com/tokio-rs/axum/pull/1086
|
||||
[#1088]: https://github.com/tokio-rs/axum/pull/1088
|
||||
[#1102]: https://github.com/tokio-rs/axum/pull/1102
|
||||
[#1119]: https://github.com/tokio-rs/axum/pull/1119
|
||||
[#1152]: https://github.com/tokio-rs/axum/pull/1152
|
||||
[#1155]: https://github.com/tokio-rs/axum/pull/1155
|
||||
[#1239]: https://github.com/tokio-rs/axum/pull/1239
|
||||
[#1248]: https://github.com/tokio-rs/axum/pull/1248
|
||||
[#1272]: https://github.com/tokio-rs/axum/pull/1272
|
||||
[#1301]: https://github.com/tokio-rs/axum/pull/1301
|
||||
[#1302]: https://github.com/tokio-rs/axum/pull/1302
|
||||
[#1327]: https://github.com/tokio-rs/axum/pull/1327
|
||||
[#1342]: https://github.com/tokio-rs/axum/pull/1342
|
||||
[#1346]: https://github.com/tokio-rs/axum/pull/1346
|
||||
[#1352]: https://github.com/tokio-rs/axum/pull/1352
|
||||
[#1368]: https://github.com/tokio-rs/axum/pull/1368
|
||||
[#1371]: https://github.com/tokio-rs/axum/pull/1371
|
||||
[#1382]: https://github.com/tokio-rs/axum/pull/1382
|
||||
[#1387]: https://github.com/tokio-rs/axum/pull/1387
|
||||
[#1389]: https://github.com/tokio-rs/axum/pull/1389
|
||||
[#1396]: https://github.com/tokio-rs/axum/pull/1396
|
||||
[#1397]: https://github.com/tokio-rs/axum/pull/1397
|
||||
[#1400]: https://github.com/tokio-rs/axum/pull/1400
|
||||
[#1408]: https://github.com/tokio-rs/axum/pull/1408
|
||||
[#1414]: https://github.com/tokio-rs/axum/pull/1414
|
||||
[#1418]: https://github.com/tokio-rs/axum/pull/1418
|
||||
[#1420]: https://github.com/tokio-rs/axum/pull/1420
|
||||
[#1421]: https://github.com/tokio-rs/axum/pull/1421
|
||||
[#1430]: https://github.com/tokio-rs/axum/pull/1430
|
||||
[#1462]: https://github.com/tokio-rs/axum/pull/1462
|
||||
[#1487]: https://github.com/tokio-rs/axum/pull/1487
|
||||
[#1496]: https://github.com/tokio-rs/axum/pull/1496
|
||||
[#1521]: https://github.com/tokio-rs/axum/pull/1521
|
||||
[#1529]: https://github.com/tokio-rs/axum/pull/1529
|
||||
[#1532]: https://github.com/tokio-rs/axum/pull/1532
|
||||
[#1539]: https://github.com/tokio-rs/axum/pull/1539
|
||||
[#1552]: https://github.com/tokio-rs/axum/pull/1552
|
||||
[`axum-macros`]: https://docs.rs/axum-macros/latest/axum_macros/
|
||||
[`parse-body-based-on-content-type`]: https://github.com/tokio-rs/axum/blob/main/examples/parse-body-based-on-content-type/src/main.rs
|
||||
|
||||
<details>
|
||||
<summary>0.6.0 Pre-Releases</summary>
|
||||
|
||||
# 0.6.0-rc.5 (18. November, 2022)
|
||||
|
||||
|
@ -527,6 +961,8 @@ Yanked, as it didn't compile in release mode.
|
|||
[#1302]: https://github.com/tokio-rs/axum/pull/1302
|
||||
[#924]: https://github.com/tokio-rs/axum/pull/924
|
||||
|
||||
</details>
|
||||
|
||||
# 0.5.16 (10. September, 2022)
|
||||
|
||||
## Security
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "axum"
|
||||
version = "0.6.0-rc.5"
|
||||
version = "0.6.0"
|
||||
categories = ["asynchronous", "network-programming", "web-programming::http-server"]
|
||||
description = "Web framework that focuses on ergonomics and modularity"
|
||||
edition = "2021"
|
||||
|
@ -31,7 +31,7 @@ __private_docs = ["tower/full", "tower-http/full"]
|
|||
|
||||
[dependencies]
|
||||
async-trait = "0.1.43"
|
||||
axum-core = { path = "../axum-core", version = "=0.3.0-rc.3" }
|
||||
axum-core = { path = "../axum-core", version = "0.3.0" }
|
||||
bitflags = "1.0"
|
||||
bytes = "1.0"
|
||||
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
|
||||
|
@ -52,7 +52,7 @@ tower-layer = "0.3.2"
|
|||
tower-service = "0.3"
|
||||
|
||||
# optional dependencies
|
||||
axum-macros = { path = "../axum-macros", version = "=0.3.0-rc.3", optional = true }
|
||||
axum-macros = { path = "../axum-macros", version = "0.3.0", optional = true }
|
||||
base64 = { version = "0.13", optional = true }
|
||||
headers = { version = "0.3.7", optional = true }
|
||||
multer = { version = "2.0.0", optional = true }
|
||||
|
|
Loading…
Reference in a new issue