diff --git a/actix-http/src/body/either.rs b/actix-http/src/body/either.rs index add1eab7c..92bd89984 100644 --- a/actix-http/src/body/either.rs +++ b/actix-http/src/body/either.rs @@ -10,6 +10,17 @@ use super::{BodySize, BoxBody, MessageBody}; use crate::Error; pin_project! { + /// An "either" type specialized for body types. + /// + /// It is common, in middleware especially, to conditionally return an inner service's unknown/ + /// generic body `B` type or return early with a new response. This type's "right" variant + /// defaults to `BoxBody` since error responses are the common case. + /// + /// For example, middleware will often have `type Response = ServiceResponse>`. + /// This means that the inner service's response body type maps to the `Left` variant and the + /// middleware's own error responses use the default `Right` variant of `BoxBody`. Of course, + /// there's no reason it couldn't use `EitherBody` instead if its alternative + /// responses have a known type. #[project = EitherBodyProj] #[derive(Debug, Clone)] pub enum EitherBody { @@ -22,7 +33,10 @@ pin_project! { } impl EitherBody { - /// Creates new `EitherBody` using left variant and boxed right variant. + /// Creates new `EitherBody` left variant with a boxed right variant. + /// + /// If the expected `R` type will be inferred and is not `BoxBody` then use the + /// [`left`](Self::left) constructor instead. #[inline] pub fn new(body: L) -> Self { Self::Left { body } diff --git a/actix-http/src/body/message_body.rs b/actix-http/src/body/message_body.rs index 86ff09fbe..9090e34d5 100644 --- a/actix-http/src/body/message_body.rs +++ b/actix-http/src/body/message_body.rs @@ -19,7 +19,7 @@ use super::{BodySize, BoxBody}; /// It is not usually necessary to create custom body types, this trait is already [implemented for /// a large number of sensible body types](#foreign-impls) including: /// - Empty body: `()` -/// - Text-based: `String`, `&'static str`, `ByteString`. +/// - Text-based: `String`, `&'static str`, [`ByteString`](https://docs.rs/bytestring/1). /// - Byte-based: `Bytes`, `BytesMut`, `Vec`, `&'static [u8]`; /// - Streams: [`BodyStream`](super::BodyStream), [`SizedStream`](super::SizedStream) /// diff --git a/actix-web/MIGRATION-4.0.md b/actix-web/MIGRATION-4.0.md index e71387c94..d478456fa 100644 --- a/actix-web/MIGRATION-4.0.md +++ b/actix-web/MIGRATION-4.0.md @@ -19,7 +19,7 @@ Headings marked with :warning: are **breaking behavioral changes** and will prob - [Removed `awc` Client Re-export](#removed-awc-client-re-export) - [Integration Testing Utils Moved To `actix-test`](#integration-testing-utils-moved-to-actix-test) - [Header APIs](#header-apis) -- [Body Types / Removal of Body+ResponseBody types / Addition of EitherBody](#body-types--removal-of-bodyresponsebody-types--addition-of-eitherbody) +- [Response Body Types](#response-body-types) - [Middleware Trait APIs](#middleware-trait-apis) - [`Responder` Trait](#responder-trait) - [`App::data` Deprecation :warning:](#appdata-deprecation-warning) @@ -131,15 +131,40 @@ For request and response builder APIs, the new methods provide a unified interfa + .insert_header(ContentType::json()) ``` -## Body Types / Removal of Body+ResponseBody types / Addition of EitherBody +## Response Body Types -TODO +There have been a lot of changes to response body types. The general theme is that they are now more expressive and their purposes are more obvious. -In particular, folks seem to be struggling with the `ErrorHandlers` middleware because of this change and the obscured nature of `EitherBody` within its types. +All items in the [`body` module](https://docs.rs/actix-web/4/actix_web/body) have much better documentation now. + +### `ResponseBody` + +`ResponseBody` is gone. Its purpose was confusing and has been replaced by better components. + +### `Body` + +`Body` is also gone. In combination with `ResponseBody`, the API it provided was sub-optimal and did not encourage expressive types. Here are the equivalents in the new system (check docs): + +- `Body::None` => `body::None::new()` +- `Body::Empty` => `()` / `web::Bytes::new()` +- `Body::Bytes` => `web::Bytes::from(...)` +- `Body::Message` => `.boxed()` / `BoxBody` + +### `BoxBody` + +`BoxBody` is a new type erased body type. It's used for all error response bodies use this. Creating a boxed body is best done by calling [`.boxed()`](https://docs.rs/actix-web/4/actix_web/body/trait.MessageBody.html#method.boxed) on a `MessageBody` type. + +### `EitherBody` + +`EitherBody` is a new "either" type that is particularly useful in middleware that can bail early, returning their own response plus body type. + +### Error Handlers + +TODO In particular, folks seem to be struggling with the `ErrorHandlers` middleware because of this change and the obscured nature of `EitherBody` within its types. ## Middleware Trait APIs -> This section builds upon guidance from the [response body types](#body-types--removal-of-bodyresponsebody-types--addition-of-eitherbody) section. +This section builds upon guidance from the [response body types](#response-body-types) section. TODO @@ -149,7 +174,7 @@ TODO: Also write the Middleware author's guide. The `Responder` trait's interface has changed. Errors should be handled and converted to responses within the `respond_to` method. It's also no longer async so the associated `type Future` has been removed; there was no compelling use case found for it. These changes simplify the interface and implementation a lot. -Now that more emphasis is placed on expressive body types, as explained in the [body types migration section](#body-types--removal-of-bodyresponsebody-types--addition-of-eitherbody), this trait has introduced an associated `type Body`. The simplest migration will be to use `BoxBody` + `.map_into_boxed_body()` but if there is a more expressive type for your responder then try to use that instead. +Now that more emphasis is placed on expressive body types, as explained in the [body types migration section](#response-body-types), this trait has introduced an associated `type Body`. The simplest migration will be to use `BoxBody` + `.map_into_boxed_body()` but if there is a more expressive type for your responder then try to use that instead. ```diff impl Responder for &'static str {