server_fn/codec/mod.rs
1//! The serialization/deserialization process for server functions consists of a series of steps,
2//! each of which is represented by a different trait:
3//! 1. [`IntoReq`]: The client serializes the [`ServerFn`] argument type into an HTTP request.
4//! 2. The [`Client`] sends the request to the server.
5//! 3. [`FromReq`]: The server deserializes the HTTP request back into the [`ServerFn`] type.
6//! 4. The server calls [`ServerFn::run_body`] on the data.
7//! 5. [`IntoRes`]: The server serializes the [`ServerFn::Output`] type into an HTTP response.
8//! 6. The server integration applies any middleware from [`ServerFn::middlewares`] and responds to the request.
9//! 7. [`FromRes`]: The client deserializes the response back into the [`ServerFn::Output`] type.
10//!
11//! Rather than a limited number of encodings, this crate allows you to define server functions that
12//! mix and match the input encoding and output encoding. To define a new encoding, you simply implement
13//! an input combination ([`IntoReq`] and [`FromReq`]) and/or an output encoding ([`IntoRes`] and [`FromRes`]).
14//! This genuinely is an and/or: while some encodings can be used for both input and output (`Json`, `Cbor`, `Rkyv`),
15//! others can only be used for input (`GetUrl`, `MultipartData`).
16
17#[cfg(feature = "cbor")]
18mod cbor;
19#[cfg(feature = "cbor")]
20pub use cbor::*;
21
22mod json;
23pub use json::*;
24
25#[cfg(feature = "serde-lite")]
26mod serde_lite;
27#[cfg(feature = "serde-lite")]
28pub use serde_lite::*;
29
30#[cfg(feature = "rkyv")]
31mod rkyv;
32#[cfg(feature = "rkyv")]
33pub use rkyv::*;
34
35mod url;
36pub use url::*;
37
38#[cfg(feature = "multipart")]
39mod multipart;
40#[cfg(feature = "multipart")]
41pub use multipart::*;
42
43#[cfg(feature = "msgpack")]
44mod msgpack;
45#[cfg(feature = "msgpack")]
46pub use msgpack::*;
47
48#[cfg(feature = "postcard")]
49mod postcard;
50#[cfg(feature = "postcard")]
51pub use postcard::*;
52
53#[cfg(feature = "bitcode")]
54mod bitcode;
55#[cfg(feature = "bitcode")]
56pub use bitcode::*;
57
58#[cfg(feature = "bitcode-serde")]
59mod bitcode_serde;
60#[cfg(feature = "bitcode-serde")]
61pub use bitcode_serde::*;
62
63mod patch;
64pub use patch::*;
65mod post;
66pub use post::*;
67mod put;
68pub use put::*;
69mod stream;
70use crate::ContentType;
71use futures::Future;
72use http::Method;
73pub use stream::*;
74
75/// Serializes a data type into an HTTP request, on the client.
76///
77/// Implementations use the methods of the [`ClientReq`](crate::request::ClientReq) trait to
78/// convert data into a request body. They are often quite short, usually consisting
79/// of just two steps:
80/// 1. Serializing the data into some [`String`], [`Bytes`](bytes::Bytes), or [`Stream`](futures::Stream).
81/// 2. Creating a request with a body of that type.
82///
83/// For example, here’s the implementation for [`Json`].
84///
85/// ```rust,ignore
86/// impl<E, T, Request> IntoReq<Json, Request, E> for T
87/// where
88/// Request: ClientReq<E>,
89/// T: Serialize + Send,
90/// {
91/// fn into_req(
92/// self,
93/// path: &str,
94/// accepts: &str,
95/// ) -> Result<Request, E> {
96/// // try to serialize the data
97/// let data = serde_json::to_string(&self)
98/// .map_err(|e| ServerFnErrorErr::Serialization(e.to_string()).into_app_error())?;
99/// // and use it as the body of a POST request
100/// Request::try_new_post(path, accepts, Json::CONTENT_TYPE, data)
101/// }
102/// }
103/// ```
104pub trait IntoReq<Encoding, Request, E> {
105 /// Attempts to serialize the arguments into an HTTP request.
106 fn into_req(self, path: &str, accepts: &str) -> Result<Request, E>;
107}
108
109/// Deserializes an HTTP request into the data type, on the server.
110///
111/// Implementations use the methods of the [`Req`](crate::Req) trait to access whatever is
112/// needed from the request. They are often quite short, usually consisting
113/// of just two steps:
114/// 1. Extracting the request body into some [`String`], [`Bytes`](bytes::Bytes), or [`Stream`](futures::Stream).
115/// 2. Deserializing that data into the data type.
116///
117/// For example, here’s the implementation for [`Json`].
118///
119/// ```rust,ignore
120/// impl<E, T, Request> FromReq<Json, Request, E> for T
121/// where
122/// // require the Request implement `Req`
123/// Request: Req<E> + Send + 'static,
124/// // require that the type can be deserialized with `serde`
125/// T: DeserializeOwned,
126/// E: FromServerFnError,
127/// {
128/// async fn from_req(
129/// req: Request,
130/// ) -> Result<Self, E> {
131/// // try to convert the body of the request into a `String`
132/// let string_data = req.try_into_string().await?;
133/// // deserialize the data
134/// serde_json::from_str(&string_data)
135/// .map_err(|e| ServerFnErrorErr::Args(e.to_string()).into_app_error())
136/// }
137/// }
138/// ```
139pub trait FromReq<Encoding, Request, E>
140where
141 Self: Sized,
142{
143 /// Attempts to deserialize the arguments from a request.
144 fn from_req(req: Request) -> impl Future<Output = Result<Self, E>> + Send;
145}
146
147/// Serializes the data type into an HTTP response.
148///
149/// Implementations use the methods of the [`Res`](crate::Res) trait to create a
150/// response. They are often quite short, usually consisting
151/// of just two steps:
152/// 1. Serializing the data type to a [`String`], [`Bytes`](bytes::Bytes), or a [`Stream`](futures::Stream).
153/// 2. Creating a response with that serialized value as its body.
154///
155/// For example, here’s the implementation for [`Json`].
156///
157/// ```rust,ignore
158/// impl<E, T, Response> IntoRes<Json, Response, E> for T
159/// where
160/// Response: Res<E>,
161/// T: Serialize + Send,
162/// E: FromServerFnError,
163/// {
164/// async fn into_res(self) -> Result<Response, E> {
165/// // try to serialize the data
166/// let data = serde_json::to_string(&self)
167/// .map_err(|e| ServerFnErrorErr::Serialization(e.to_string()).into())?;
168/// // and use it as the body of a response
169/// Response::try_from_string(Json::CONTENT_TYPE, data)
170/// }
171/// }
172/// ```
173pub trait IntoRes<Encoding, Response, E> {
174 /// Attempts to serialize the output into an HTTP response.
175 fn into_res(self) -> impl Future<Output = Result<Response, E>> + Send;
176}
177
178/// Deserializes the data type from an HTTP response.
179///
180/// Implementations use the methods of the [`ClientRes`](crate::ClientRes) trait to extract
181/// data from a response. They are often quite short, usually consisting
182/// of just two steps:
183/// 1. Extracting a [`String`], [`Bytes`](bytes::Bytes), or a [`Stream`](futures::Stream)
184/// from the response body.
185/// 2. Deserializing the data type from that value.
186///
187/// For example, here’s the implementation for [`Json`].
188///
189/// ```rust,ignore
190/// impl<E, T, Response> FromRes<Json, Response, E> for T
191/// where
192/// Response: ClientRes<E> + Send,
193/// T: DeserializeOwned + Send,
194/// E: FromServerFnError,
195/// {
196/// async fn from_res(
197/// res: Response,
198/// ) -> Result<Self, E> {
199/// // extracts the request body
200/// let data = res.try_into_string().await?;
201/// // and tries to deserialize it as JSON
202/// serde_json::from_str(&data)
203/// .map_err(|e| ServerFnErrorErr::Deserialization(e.to_string()).into_app_error())
204/// }
205/// }
206/// ```
207pub trait FromRes<Encoding, Response, E>
208where
209 Self: Sized,
210{
211 /// Attempts to deserialize the outputs from a response.
212 fn from_res(res: Response) -> impl Future<Output = Result<Self, E>> + Send;
213}
214
215/// Defines a particular encoding format, which can be used for serializing or deserializing data.
216pub trait Encoding: ContentType {
217 /// The HTTP method used for requests.
218 ///
219 /// This should be `POST` in most cases.
220 const METHOD: Method;
221}