pavex/response/body/
mod.rs

1//! Tools for building and manipulating [`Response`](crate::Response) bodies.
2//!
3//! Check out [`Response::set_typed_body`] for more details.
4//!
5//! [`Response::set_typed_body`]: crate::Response::set_typed_body
6pub use html::Html;
7pub use json::Json;
8pub use typed_body::TypedBody;
9
10pub(super) mod body_;
11mod bytes;
12mod html;
13mod json;
14mod plain_text;
15pub mod raw;
16
17pub mod errors;
18
19mod typed_body {
20    use crate::http::HeaderValue;
21
22    use super::raw::Bytes;
23    use super::raw::RawBody;
24
25    /// A trait that ties together a [`Response`] body with
26    /// its expected `Content-Type` header.
27    ///
28    /// Check out [`Response::set_typed_body`](crate::Response) for more details
29    /// on `TypedBody` is leveraged when building a [`Response`].
30    ///
31    /// # Implementing `TypedBody`
32    ///
33    /// You might find yourself implementing `TypedBody` if none of the implementations
34    /// provided out-of-the-box by Pavex in the [`body`](super) module satisfies your needs.
35    ///
36    /// You need to specify two things:
37    ///
38    /// 1. The value of the `Content-Type` header
39    /// 2. The low-level representation of your body type
40    ///
41    /// Let's focus on 2., the trickier bit. You'll be working with the types in
42    /// the [`body::raw`](super::raw) module.
43    ///
44    /// ## Buffered body
45    ///
46    /// [`Full<Bytes>`](super::raw::Full) is the "canonical" choice if your body is fully
47    /// buffered in memory before being transmitted over the network.
48    /// You need to convert your body type into a buffer ([`Bytes`])
49    /// which is then wrapped in [`Full`](super::raw::Full) to signal that the entire
50    /// body is a single "chunk".
51    ///
52    /// Let's see how you could implement `TypedBody` for a `String` wrapper
53    /// as a reference example:
54    ///
55    /// ```rust,
56    /// use pavex::http::HeaderValue;
57    /// use pavex::response::body::{
58    ///     TypedBody,
59    ///     raw::{Full, Bytes}
60    /// };
61    ///
62    /// struct MyString(String);
63    ///
64    /// impl TypedBody for MyString {
65    ///     type Body = Full<Bytes>;
66    ///
67    ///     fn content_type(&self) -> HeaderValue {
68    ///         HeaderValue::from_static("text/plain; charset=utf-8")
69    ///     }
70    ///
71    ///     fn body(self) -> Self::Body {
72    ///         Full::new(self.0.into())
73    ///     }
74    /// }
75    /// ```
76    ///
77    /// ## Streaming body
78    ///
79    /// Streaming bodies are trickier.
80    /// You might need to implement [`RawBody`] directly for your body type.
81    ///
82    /// [`Response`]: crate::Response
83    // TODO: expand guide for streaming bodies.
84    pub trait TypedBody {
85        type Body: RawBody<Data = Bytes> + Send + 'static;
86
87        /// The header value that should be used as `Content-Type` when
88        /// returning this [`Response`](crate::Response).
89        fn content_type(&self) -> HeaderValue;
90
91        /// The actual body type.
92        ///
93        /// It must implement the [`RawBody`] trait.
94        fn body(self) -> Self::Body;
95    }
96}