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}