mirror of
https://github.com/tokio-rs/axum.git
synced 2024-10-24 01:46:51 +02:00
Reorganize changelog (#413)
* Reorganize changelog When it starts growing this big I think grouping it into topics is nice. * misc fixes
This commit is contained in:
parent
02a035fb14
commit
0a3f69af0d
1 changed files with 126 additions and 122 deletions
248
CHANGELOG.md
248
CHANGELOG.md
|
@ -7,126 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
- **fixed:** All known compile time issues are resolved, including those with
|
- Overall:
|
||||||
`boxed` and those introduced by Rust 1.56 ([#404])
|
- **fixed:** All known compile time issues are resolved, including those with
|
||||||
- Big internal refactoring of routing leading to several improvements ([#363])
|
`boxed` and those introduced by Rust 1.56 ([#404])
|
||||||
- **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported.
|
- **breaking:** The router's type is now always `Router` regardless of how many routes or
|
||||||
- **fixed:** The order routes are added in no longer matters.
|
middleware are applies ([#404])
|
||||||
- **fixed:** Adding a conflicting route will now cause a panic instead of silently making
|
|
||||||
a route unreachable.
|
|
||||||
- **fixed:** Route matching is faster as number of routes increase.
|
|
||||||
- **breaking:** The routes `/foo` and `/:key` are considered to overlap and
|
|
||||||
will cause a panic when constructing the router. This might be fixed in the future.
|
|
||||||
- **fixed:** Expand accepted content types for JSON requests ([#378])
|
|
||||||
- **fixed:** Support deserializing `i128` and `u128` in `extract::Path`
|
|
||||||
- **breaking:** The router's type is now always `Router` regardless of how many routes or
|
|
||||||
middleware are applies ([#404])
|
|
||||||
|
|
||||||
This means router types are all always nameable:
|
This means router types are all always nameable:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn my_routes() -> Router {
|
fn my_routes() -> Router {
|
||||||
Router::new().route(
|
Router::new().route(
|
||||||
"/users",
|
"/users",
|
||||||
post(|| async { "Hello, World!" }),
|
post(|| async { "Hello, World!" }),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- **breaking:** `Route::boxed` and `BoxRoute` have been removed as they're no longer
|
- **breaking:** Added feature flags for HTTP1 and JSON. This enables removing a
|
||||||
necessary ([#404])
|
few dependencies if your app only uses HTTP2 or doesn't use JSON. Its only a
|
||||||
- **breaking:** `Route`, `Nested`, `Or` types are now private. They no longer had to be
|
breaking change if you depend on axum with `default_features = false`. ([#286])
|
||||||
public because `Router` is internally boxed ([#404])
|
- **breaking:** `Route::boxed` and `BoxRoute` have been removed as they're no longer
|
||||||
- **breaking:** Automatically do percent decoding in `extract::Path`
|
necessary ([#404])
|
||||||
([#272])
|
- **breaking:** `Route`, `Nested`, `Or` types are now private. They no longer had to be
|
||||||
- **breaking:** Added feature flags for HTTP1 and JSON. This enables removing a
|
public because `Router` is internally boxed ([#404])
|
||||||
few dependencies if your app only uses HTTP2 or doesn't use JSON. Its only a
|
- **breaking:** Remove `routing::Layered` as it didn't actually do anything and
|
||||||
breaking change if you depend on axum with `default_features = false`. ([#286])
|
thus wasn't necessary
|
||||||
- **breaking:** Remove `routing::Layered` as it didn't actually do anything and
|
- Routing:
|
||||||
thus wasn't necessary
|
- Big internal refactoring of routing leading to several improvements ([#363])
|
||||||
- **breaking:** Change `Connected::connect_info` to return `Self` and remove
|
- **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported.
|
||||||
the associated type `ConnectInfo` ([#396])
|
- **fixed:** The order routes are added in no longer matters.
|
||||||
- **breaking:** Simplify error handling model ([#402]):
|
- **fixed:** Adding a conflicting route will now cause a panic instead of silently making
|
||||||
- All services part of the router are now required to be infallible.
|
a route unreachable.
|
||||||
- Error handling utilities have been moved to an `error_handling` module.
|
- **fixed:** Route matching is faster as number of routes increase.
|
||||||
- `Router::check_infallible` has been removed since routers are always
|
- **breaking:** The routes `/foo` and `/:key` are considered to overlap and
|
||||||
infallible with the error handling changes.
|
will cause a panic when constructing the router. This might be fixed in the future.
|
||||||
- Error handling closures must now handle all errors and thus always return
|
- **fixed:** Middleware that return early (such as `tower_http::auth::RequireAuthorization`)
|
||||||
something that implements `IntoResponse`.
|
now no longer catch requests that would otherwise be 404s. They also work
|
||||||
|
correctly with `Router::merge` (previously called `or`) ([#408])
|
||||||
With these changes handling errors from fallible middleware is done like so:
|
- **fixed:** Correctly handle trailing slashes in routes:
|
||||||
|
|
||||||
```rust,no_run
|
|
||||||
use axum::{
|
|
||||||
routing::get,
|
|
||||||
http::StatusCode,
|
|
||||||
error_handling::HandleErrorLayer,
|
|
||||||
response::IntoResponse,
|
|
||||||
Router, BoxError,
|
|
||||||
};
|
|
||||||
use tower::ServiceBuilder;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
let middleware_stack = ServiceBuilder::new()
|
|
||||||
// Handle errors from middleware
|
|
||||||
//
|
|
||||||
// This middleware most be added above any fallible
|
|
||||||
// ones if you're using `ServiceBuilder`, due to how ordering works
|
|
||||||
.layer(HandleErrorLayer::new(handle_error))
|
|
||||||
// Return an error after 30 seconds
|
|
||||||
.timeout(Duration::from_secs(30));
|
|
||||||
|
|
||||||
let app = Router::new()
|
|
||||||
.route("/", get(|| async { /* ... */ }))
|
|
||||||
.layer(middleware_stack);
|
|
||||||
|
|
||||||
fn handle_error(_error: BoxError) -> impl IntoResponse {
|
|
||||||
StatusCode::REQUEST_TIMEOUT
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And handling errors from fallible leaf services is done like so:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use axum::{
|
|
||||||
Router, service,
|
|
||||||
body::Body,
|
|
||||||
routing::service_method_router::get,
|
|
||||||
response::IntoResponse,
|
|
||||||
http::{Request, Response},
|
|
||||||
error_handling::HandleErrorExt, // for `.handle_error`
|
|
||||||
};
|
|
||||||
use std::{io, convert::Infallible};
|
|
||||||
use tower::service_fn;
|
|
||||||
|
|
||||||
let app = Router::new()
|
|
||||||
.route(
|
|
||||||
"/",
|
|
||||||
get(service_fn(|_req: Request<Body>| async {
|
|
||||||
let contents = tokio::fs::read_to_string("some_file").await?;
|
|
||||||
Ok::<_, io::Error>(Response::new(Body::from(contents)))
|
|
||||||
}))
|
|
||||||
.handle_error(handle_io_error),
|
|
||||||
);
|
|
||||||
|
|
||||||
fn handle_io_error(error: io::Error) -> impl IntoResponse {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- **breaking:** Method routing for handlers have been moved from `axum::handler`
|
|
||||||
to `axum::routing`. So `axum::handler::get` now lives at `axum::routing::get`
|
|
||||||
([#405])
|
|
||||||
- **breaking:** Method routing for services have been moved from `axum::service`
|
|
||||||
to `axum::routing`. So `axum::service::get` now lives at
|
|
||||||
`axum::service_method_router::get` ([#405])
|
|
||||||
- **breaking:** `Router::or` renamed to `Router::merge` and will now panic on
|
|
||||||
overlapping routes. It now only accepts `Router`s and not general `Service`s.
|
|
||||||
Use `Router::fallback` for adding fallback routes ([#408])
|
|
||||||
- **added:** `Router::fallback` for adding handlers for request that didn't
|
|
||||||
match any routes ([#408])
|
|
||||||
- **fixed:** Middleware that return early (such as `tower_http::auth::RequireAuthorization`)
|
|
||||||
now no longer catch requests that would otherwise be 404s. They also work
|
|
||||||
correctly with `Router::merge` (previously called `or`) ([#408])
|
|
||||||
- **fixed:** Correctly handle trailing slashes in routes:
|
|
||||||
- If a route with a trailing slash exists and a request without a trailing
|
- If a route with a trailing slash exists and a request without a trailing
|
||||||
slash is received, axum will send a 301 redirection to the route with the
|
slash is received, axum will send a 301 redirection to the route with the
|
||||||
trailing slash.
|
trailing slash.
|
||||||
|
@ -134,10 +52,96 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
with a trailing slash is received.
|
with a trailing slash is received.
|
||||||
- This can be overridden by explicitly defining two routes: One with and one
|
- This can be overridden by explicitly defining two routes: One with and one
|
||||||
without trailing a slash.
|
without trailing a slash.
|
||||||
- **breaking:** `EmptyRouter` has been renamed to `MethodNotAllowed` as its only
|
- **breaking:** Method routing for handlers have been moved from `axum::handler`
|
||||||
used in method routers and not in path routers (`Router`)
|
to `axum::routing`. So `axum::handler::get` now lives at `axum::routing::get`
|
||||||
- **added:** Add `extract::MatchedPath` for accessing path in router that
|
([#405])
|
||||||
matched request ([#412])
|
- **breaking:** Method routing for services have been moved from `axum::service`
|
||||||
|
to `axum::routing`. So `axum::service::get` now lives at, etc.
|
||||||
|
`axum::routing::service_method_router::get`, etc. ([#405])
|
||||||
|
- **breaking:** `Router::or` renamed to `Router::merge` and will now panic on
|
||||||
|
overlapping routes. It now only accepts `Router`s and not general `Service`s.
|
||||||
|
Use `Router::fallback` for adding fallback routes ([#408])
|
||||||
|
- **added:** `Router::fallback` for adding handlers for request that didn't
|
||||||
|
match any routes ([#408])
|
||||||
|
- **breaking:** `EmptyRouter` has been renamed to `MethodNotAllowed` as its only
|
||||||
|
used in method routers and not in path routers (`Router`)
|
||||||
|
- Extractors:
|
||||||
|
- **fixed:** Expand accepted content types for JSON requests ([#378])
|
||||||
|
- **fixed:** Support deserializing `i128` and `u128` in `extract::Path`
|
||||||
|
- **breaking:** Automatically do percent decoding in `extract::Path`
|
||||||
|
([#272])
|
||||||
|
- **breaking:** Change `Connected::connect_info` to return `Self` and remove
|
||||||
|
the associated type `ConnectInfo` ([#396])
|
||||||
|
- **added:** Add `extract::MatchedPath` for accessing path in router that
|
||||||
|
matched request ([#412])
|
||||||
|
- Error handling:
|
||||||
|
- **breaking:** Simplify error handling model ([#402]):
|
||||||
|
- All services part of the router are now required to be infallible.
|
||||||
|
- Error handling utilities have been moved to an `error_handling` module.
|
||||||
|
- `Router::check_infallible` has been removed since routers are always
|
||||||
|
infallible with the error handling changes.
|
||||||
|
- Error handling closures must now handle all errors and thus always return
|
||||||
|
something that implements `IntoResponse`.
|
||||||
|
|
||||||
|
With these changes handling errors from fallible middleware is done like so:
|
||||||
|
|
||||||
|
```rust,no_run
|
||||||
|
use axum::{
|
||||||
|
routing::get,
|
||||||
|
http::StatusCode,
|
||||||
|
error_handling::HandleErrorLayer,
|
||||||
|
response::IntoResponse,
|
||||||
|
Router, BoxError,
|
||||||
|
};
|
||||||
|
use tower::ServiceBuilder;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
let middleware_stack = ServiceBuilder::new()
|
||||||
|
// Handle errors from middleware
|
||||||
|
//
|
||||||
|
// This middleware most be added above any fallible
|
||||||
|
// ones if you're using `ServiceBuilder`, due to how ordering works
|
||||||
|
.layer(HandleErrorLayer::new(handle_error))
|
||||||
|
// Return an error after 30 seconds
|
||||||
|
.timeout(Duration::from_secs(30));
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.route("/", get(|| async { /* ... */ }))
|
||||||
|
.layer(middleware_stack);
|
||||||
|
|
||||||
|
fn handle_error(_error: BoxError) -> impl IntoResponse {
|
||||||
|
StatusCode::REQUEST_TIMEOUT
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And handling errors from fallible leaf services is done like so:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use axum::{
|
||||||
|
Router, service,
|
||||||
|
body::Body,
|
||||||
|
routing::service_method_router::get,
|
||||||
|
response::IntoResponse,
|
||||||
|
http::{Request, Response},
|
||||||
|
error_handling::HandleErrorExt, // for `.handle_error`
|
||||||
|
};
|
||||||
|
use std::{io, convert::Infallible};
|
||||||
|
use tower::service_fn;
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.route(
|
||||||
|
"/",
|
||||||
|
get(service_fn(|_req: Request<Body>| async {
|
||||||
|
let contents = tokio::fs::read_to_string("some_file").await?;
|
||||||
|
Ok::<_, io::Error>(Response::new(Body::from(contents)))
|
||||||
|
}))
|
||||||
|
.handle_error(handle_io_error),
|
||||||
|
);
|
||||||
|
|
||||||
|
fn handle_io_error(error: io::Error) -> impl IntoResponse {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
[#339]: https://github.com/tokio-rs/axum/pull/339
|
[#339]: https://github.com/tokio-rs/axum/pull/339
|
||||||
[#286]: https://github.com/tokio-rs/axum/pull/286
|
[#286]: https://github.com/tokio-rs/axum/pull/286
|
||||||
|
|
Loading…
Reference in a new issue