-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix compile time regression by boxing routes internally #404
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
davidpdrsn
force-pushed
the
box-routes-internally-2
branch
from
October 24, 2021 18:34
0c79126
to
6851d01
Compare
This was referenced Oct 24, 2021
Merged
davidpdrsn
added a commit
that referenced
this pull request
Oct 25, 2021
With #404 and #402 all routes now have the same types and thus we don't need to nest them but can instead store them all in a map. This simplifies the routing quite a bit and is faster as well. High level changes: - Routes are now stored in a `HashMap<RouteId, Route<B>>`. - `Router::or` is renamed to `Router::merge` because thats what it does now. It copies all routes from one router to another. This also means overlapping routes will cause a panic which is nice win. - `Router::merge` now only accepts `Router`s so added `Router::fallback` for adding a global 404 handler. - The `Or` service has been removed. - `Router::layer` now only adds layers to the routes you actually have meaning middleware runs _after_ routing. I believe that addresses #380 but will test that on another branch.
davidpdrsn
added a commit
that referenced
this pull request
Nov 2, 2021
- Overall: - **fixed:** All known compile time issues are resolved, including those with `boxed` and those introduced by Rust 1.56 ([#404]) - **breaking:** The router's type is now always `Router` regardless of how many routes or middleware are applied ([#404]) This means router types are all always nameable: ```rust fn my_routes() -> Router { Router::new().route( "/users", post(|| async { "Hello, World!" }), ) } ``` - **breaking:** Added feature flags for HTTP1 and JSON. This enables removing a few dependencies if your app only uses HTTP2 or doesn't use JSON. Its only a breaking change if you depend on axum with `default_features = false`. ([#286]) - **breaking:** `Route::boxed` and `BoxRoute` have been removed as they're no longer necessary ([#404]) - **breaking:** `Nested`, `Or` types are now private. They no longer had to be public because `Router` is internally boxed ([#404]) - **breaking:** Remove `routing::Layered` as it didn't actually do anything and thus wasn't necessary - **breaking:** Vendor `AddExtensionLayer` and `AddExtension` to reduce public dependencies - **breaking:** `body::BoxBody` is now a type alias for `http_body::combinators::UnsyncBoxBody` and thus is no longer `Sync`. This is because bodies are streams and requiring streams to be `Sync` is unnecessary. - **added:** Implement `IntoResponse` for `http_body::combinators::UnsyncBoxBody`. - **added:** Add `Handler::into_make_service` for serving a handler without a `Router`. - **added:** Add `Handler::into_make_service_with_connect_info` for serving a handler without a `Router`, and storing info about the incoming connection. - **breaking:** axum's minimum support rust version is not 1.54 - Routing: - Big internal refactoring of routing leading to several improvements ([#363]) - **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported. - **fixed:** The order routes are added in no longer matters. - **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. - **fixed:** Correctly handle trailing slashes in routes: - 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 trailing slash. - Or vice versa if a route without a trailing slash exists and a request with a trailing slash is received. - This can be overridden by explicitly defining two routes: One with and one without trailing a slash. - **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, etc. `axum::routing::service_method_routing::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. `Router::fallback` must be use instead of `nest("/", _)` ([#408]) - **breaking:** `EmptyRouter` has been renamed to `MethodNotAllowed` as its only used in method routers and not in path routers (`Router`) - **breaking:** Remove support for routing based on the `CONNECT` method. An example of combining axum with and HTTP proxy can be found [here][proxy] ([#428]) - 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 the 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_routing::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 { // ... } ``` - Misc: - `InvalidWebsocketVersionHeader` has been renamed to `InvalidWebSocketVersionHeader` ([#416]) - `WebsocketKeyHeaderMissing` has been renamed to `WebSocketKeyHeaderMissing` ([#416]) [#339]: #339 [#286]: #286 [#272]: #272 [#378]: #378 [#363]: #363 [#396]: #396 [#402]: #402 [#404]: #404 [#405]: #405 [#408]: #408 [#412]: #412 [#416]: #416 [#428]: #428 [proxy]: https://github.com/tokio-rs/axum/blob/main/examples/http-proxy/src/main.rs
Merged
davidpdrsn
added a commit
that referenced
this pull request
Nov 2, 2021
- Overall: - **fixed:** All known compile time issues are resolved, including those with `boxed` and those introduced by Rust 1.56 ([#404]) - **breaking:** The router's type is now always `Router` regardless of how many routes or middleware are applied ([#404]) This means router types are all always nameable: ```rust fn my_routes() -> Router { Router::new().route( "/users", post(|| async { "Hello, World!" }), ) } ``` - **breaking:** Added feature flags for HTTP1 and JSON. This enables removing a few dependencies if your app only uses HTTP2 or doesn't use JSON. Its only a breaking change if you depend on axum with `default_features = false`. ([#286]) - **breaking:** `Route::boxed` and `BoxRoute` have been removed as they're no longer necessary ([#404]) - **breaking:** `Nested`, `Or` types are now private. They no longer had to be public because `Router` is internally boxed ([#404]) - **breaking:** Remove `routing::Layered` as it didn't actually do anything and thus wasn't necessary - **breaking:** Vendor `AddExtensionLayer` and `AddExtension` to reduce public dependencies - **breaking:** `body::BoxBody` is now a type alias for `http_body::combinators::UnsyncBoxBody` and thus is no longer `Sync`. This is because bodies are streams and requiring streams to be `Sync` is unnecessary. - **added:** Implement `IntoResponse` for `http_body::combinators::UnsyncBoxBody`. - **added:** Add `Handler::into_make_service` for serving a handler without a `Router`. - **added:** Add `Handler::into_make_service_with_connect_info` for serving a handler without a `Router`, and storing info about the incoming connection. - **breaking:** axum's minimum support rust version is not 1.54 - Routing: - Big internal refactoring of routing leading to several improvements ([#363]) - **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported. - **fixed:** The order routes are added in no longer matters. - **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. - **fixed:** Correctly handle trailing slashes in routes: - 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 trailing slash. - Or vice versa if a route without a trailing slash exists and a request with a trailing slash is received. - This can be overridden by explicitly defining two routes: One with and one without trailing a slash. - **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, etc. `axum::routing::service_method_routing::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. `Router::fallback` must be use instead of `nest("/", _)` ([#408]) - **breaking:** `EmptyRouter` has been renamed to `MethodNotAllowed` as its only used in method routers and not in path routers (`Router`) - **breaking:** Remove support for routing based on the `CONNECT` method. An example of combining axum with and HTTP proxy can be found [here][proxy] ([#428]) - 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 the 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_routing::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 { // ... } ``` - Misc: - `InvalidWebsocketVersionHeader` has been renamed to `InvalidWebSocketVersionHeader` ([#416]) - `WebsocketKeyHeaderMissing` has been renamed to `WebSocketKeyHeaderMissing` ([#416]) [#339]: #339 [#286]: #286 [#272]: #272 [#378]: #378 [#363]: #363 [#396]: #396 [#402]: #402 [#404]: #404 [#405]: #405 [#408]: #408 [#412]: #412 [#416]: #416 [#428]: #428 [proxy]: https://github.com/tokio-rs/axum/blob/main/examples/http-proxy/src/main.rs
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a reimplementation of #401 but with the new matchit based router.
Fixes #399