Files
axum/axum/CHANGELOG.md
T
David Pedersen ba4d8a2357 Move axum crate into workspace subfolder (#458)
* Move axum crate into workspace subfolder

Over time I imagine we're gonna have other crates in this repo that
provide utilities or integrations for axum. This prepares for that by
moving the main axum crate into its own folder.

The README situation is a bit annoying because we want `./README.md`
for viewing the repo on github but `axum/README.md` for crates.io. For
now I've just copy/pasted it and added CI step to make sure they're
identical.

* update changelog link

* Add licenses to all examples

* is this how you install `diff`?

* or maybe this is how?

* fix readme links

* like this?

* fix cargo-deny step

* Try making root readme a symlink

* remove compare readme step

not needed since readme in repo root is now a symlink

* Revert "Add licenses to all examples"

This reverts commit ab321b7fb9.
2021-11-03 12:38:48 +01:00

21 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

  • None

0.3.0 (02. November, 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:

      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. This is 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 supported rust version is now 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 increases.
      • breaking: Handlers for multiple HTTP methods must be added in the same Router::route call. So .route("/", get(get_handler).post(post_handler)) and not .route("/", get(get_handler)).route("/", post(post_handler)).
    • 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 a trailing slash.
    • breaking: Method routing for handlers has been moved from axum::handler to axum::routing. So axum::handler::get now lives at axum::routing::get (#405)
    • breaking: Method routing for services has been moved from axum::service to axum::routing::service_method_routing. So axum::service::get now lives at 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 Routers and not general Services. 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 it's 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 (#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:

      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:

      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)

0.2.8 (07. October, 2021)

  • Document debugging handler type errors with "axum-debug" (#372)

0.2.7 (06. October, 2021)

  • Bump minimum version of async-trait (#370)

0.2.6 (02. October, 2021)

  • Clarify that handler::any and service::any only accepts standard HTTP methods (#337)
  • Document how to customize error responses from extractors (#359)

0.2.5 (18. September, 2021)

  • Add accessors for TypedHeaderRejection fields (#317)
  • Improve docs for extractors (#327)

0.2.4 (10. September, 2021)

  • Document using StreamExt::split with WebSocket (#291)
  • Document adding middleware to multiple groups of routes (#293)

0.2.3 (26. August, 2021)

  • fixed: Fix accidental breaking change introduced by internal refactor. BoxRoute used to be Sync but was accidental made !Sync (#273)

0.2.2 (26. August, 2021)

  • fixed: Fix URI captures matching empty segments. This means requests with URI / will no longer be matched by /:key (#264)
  • fixed: Remove needless trait bounds from Router::boxed (#269)

0.2.1 (24. August, 2021)

  • added: Add Redirect::to constructor (#255)
  • added: Document how to implement IntoResponse for custom error type (#258)

0.2.0 (23. August, 2021)

  • Overall:

    • fixed: Overall compile time improvements. If you're having issues with compile time please file an issue! (#184) (#198) (#220)
    • changed: Remove prelude. Explicit imports are now required (#195)
  • Routing:

    • added: Add dedicated Router to replace the RoutingDsl trait (#214)
    • added: Add Router::or for combining routes (#108)
    • fixed: Support matching different HTTP methods for the same route that aren't defined together. So Router::new().route("/", get(...)).route("/", post(...)) now accepts both GET and POST. Previously only POST would be accepted (#224)
    • fixed: get routes will now also be called for HEAD requests but will always have the response body removed (#129)
    • changed: Replace axum::route(...) with axum::Router::new().route(...). This means there is now only one way to create a new router. Same goes for axum::routing::nest. (#215)
    • changed: Implement routing::MethodFilter via bitflags (#158)
    • changed: Move handle_error from ServiceExt to service::OnMethod (#160)

    With these changes this app using 0.1:

    use axum::{extract::Extension, prelude::*, routing::BoxRoute, AddExtensionLayer};
    
    let app = route("/", get(|| async { "hi" }))
        .nest("/api", api_routes())
        .layer(AddExtensionLayer::new(state));
    
    fn api_routes() -> BoxRoute<Body> {
        route(
            "/users",
            post(|Extension(state): Extension<State>| async { "hi from nested" }),
        )
        .boxed()
    }
    

    Becomes this in 0.2:

    use axum::{
        extract::Extension,
        handler::{get, post},
        routing::BoxRoute,
        Router,
    };
    
    let app = Router::new()
        .route("/", get(|| async { "hi" }))
        .nest("/api", api_routes());
    
    fn api_routes() -> Router<BoxRoute> {
        Router::new()
            .route(
                "/users",
                post(|Extension(state): Extension<State>| async { "hi from nested" }),
            )
            .boxed()
    }
    
  • Extractors:

    • added: Make FromRequest default to being generic over body::Body (#146)
    • added: Implement std::error::Error for all rejections (#153)
    • added: Add OriginalUri for extracting original request URI in nested services (#197)
    • added: Implement FromRequest for http::Extensions (#169)
    • added: Make RequestParts::{new, try_into_request} public so extractors can be used outside axum (#194)
    • added: Implement FromRequest for axum::body::Body (#241)
    • changed: Removed extract::UrlParams and extract::UrlParamsMap. Use extract::Path instead (#154)
    • changed: extractor_middleware now requires RequestBody: Default (#167)
    • changed: Convert RequestAlreadyExtracted to an enum with each possible error variant (#167)
    • changed: extract::BodyStream is no longer generic over the request body (#234)
    • changed: extract::Body has been renamed to extract::RawBody to avoid conflicting with body::Body (#233)
    • changed: RequestParts changes (#153)
      • method new returns an &http::Method
      • method_mut new returns an &mut http::Method
      • take_method has been removed
      • uri new returns an &http::Uri
      • uri_mut new returns an &mut http::Uri
      • take_uri has been removed
    • changed: Remove several rejection types that were no longer used (#153) (#154)
  • Responses:

    • added: Add Headers for easily customizing headers on a response (#193)
    • added: Add Redirect response (#192)
    • added: Add body::StreamBody for easily responding with a stream of byte chunks (#237)
    • changed: Add associated Body and BodyError types to IntoResponse. This is required for returning responses with bodies other than hyper::Body from handlers. See the docs for advice on how to implement IntoResponse (#86)
    • changed: tower::util::Either no longer implements IntoResponse (#229)

    This IntoResponse from 0.1:

    use axum::{http::Response, prelude::*, response::IntoResponse};
    
    struct MyResponse;
    
    impl IntoResponse for MyResponse {
        fn into_response(self) -> Response<Body> {
            Response::new(Body::empty())
        }
    }
    

    Becomes this in 0.2:

    use axum::{body::Body, http::Response, response::IntoResponse};
    
    struct MyResponse;
    
    impl IntoResponse for MyResponse {
        type Body = Body;
        type BodyError = <Self::Body as axum::body::HttpBody>::Error;
    
        fn into_response(self) -> Response<Self::Body> {
            Response::new(Body::empty())
        }
    }
    
  • SSE:

    • added: Add response::sse::Sse. This implements SSE using a response rather than a service (#98)
    • changed: Remove axum::sse. Its been replaced by axum::response::sse (#98)

    Handler using SSE in 0.1:

    use axum::{
        prelude::*,
        sse::{sse, Event},
    };
    use std::convert::Infallible;
    
    let app = route(
        "/",
        sse(|| async {
            let stream = futures::stream::iter(vec![Ok::<_, Infallible>(
                Event::default().data("hi there!"),
            )]);
            Ok::<_, Infallible>(stream)
        }),
    );
    

    Becomes this in 0.2:

    use axum::{
        handler::get,
        response::sse::{Event, Sse},
        Router,
    };
    use std::convert::Infallible;
    
    let app = Router::new().route(
        "/",
        get(|| async {
            let stream = futures::stream::iter(vec![Ok::<_, Infallible>(
                Event::default().data("hi there!"),
            )]);
            Sse::new(stream)
        }),
    );
    
  • WebSockets:

    • changed: Change WebSocket API to use an extractor plus a response (#121)
    • changed: Make WebSocket Message an enum (#116)
    • changed: WebSocket now uses Error as its error type (#150)

    Handler using WebSockets in 0.1:

    use axum::{
        prelude::*,
        ws::{ws, WebSocket},
    };
    
    let app = route(
        "/",
        ws(|socket: WebSocket| async move {
            // do stuff with socket
        }),
    );
    

    Becomes this in 0.2:

    use axum::{
        extract::ws::{WebSocket, WebSocketUpgrade},
        handler::get,
        Router,
    };
    
    let app = Router::new().route(
        "/",
        get(|ws: WebSocketUpgrade| async move {
            ws.on_upgrade(|socket: WebSocket| async move {
                // do stuff with socket
            })
        }),
    );
    
  • Misc

    • added: Add default feature tower-log which exposes tower's log feature. (#218)
    • changed: Replace body::BoxStdError with axum::Error, which supports downcasting (#150)
    • changed: EmptyRouter now requires the response body to implement Send + Sync + 'static' (#108)
    • changed: Router::check_infallible now returns a CheckInfallible service. This is to improve compile times (#198)
    • changed: Router::into_make_service now returns routing::IntoMakeService rather than tower::make::Shared (#229)
    • changed: All usage of tower::BoxError has been replaced with axum::BoxError (#229)
    • changed: Several response future types have been moved into dedicated future modules (#133)
    • changed: EmptyRouter, ExtractorMiddleware, ExtractorMiddlewareLayer, and QueryStringMissing no longer implement Copy (#132)
    • changed: service::OnMethod, handler::OnMethod, and routing::Nested have new response future types (#157)

0.1.3 (06. August, 2021)

  • Fix stripping prefix when nesting services at / (#91)
  • Add support for WebSocket protocol negotiation (#83)
  • Use pin-project-lite instead of pin-project (#95)
  • Re-export http crate and hyper::Server (#110)
  • Fix Query and Form extractors giving bad request error when query string is empty. (#117)
  • Add Path extractor. (#124)
  • Fixed the implementation of IntoResponse of (HeaderMap, T) and (StatusCode, HeaderMap, T) would ignore headers from T (#137)
  • Deprecate extract::UrlParams and extract::UrlParamsMap. Use extract::Path instead (#138)

0.1.2 (01. August, 2021)

  • Implement Stream for WebSocket (#52)
  • Implement Sink for WebSocket (#52)
  • Implement Deref most extractors (#56)
  • Return 405 Method Not Allowed for unsupported method for route (#63)
  • Add extractor for remote connection info (#55)
  • Improve error message of MissingExtension rejections (#72)
  • Improve documentation for routing (#71)
  • Clarify required response body type when routing to tower::Services (#69)
  • Add axum::body::box_body to converting an http_body::Body to axum::body::BoxBody (#69)
  • Add axum::sse for Server-Sent Events (#75)
  • Mention required dependencies in docs (#77)
  • Fix WebSockets failing on Firefox (#76)

0.1.1 (30. July, 2021)

  • Misc readme fixes.

0.1.0 (30. July, 2021)

  • Initial release.