Skip to content

Commit

Permalink
getting started on docs
Browse files Browse the repository at this point in the history
  • Loading branch information
gbj committed Jan 11, 2024
1 parent b8fdcad commit 013f5db
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 15 deletions.
15 changes: 13 additions & 2 deletions server_fn/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
use crate::{error::ServerFnError, request::ClientReq, response::ClientRes};
use std::future::Future;

/// A client defines a pair of request/response types and the logic to send
/// and receive them.
///
/// This trait is implemented for things like a browser `fetch` request or for
/// the `reqwest` trait. It should almost never be necessary to implement it
/// yourself, unless you’re trying to use an alternative HTTP crate on the client side.
pub trait Client<CustErr> {
/// The type of a request sent by this client.
type Request: ClientReq<CustErr> + Send;
/// The type of a response received by this client.
type Response: ClientRes<CustErr> + Send;

/// Sends the request and receives a response.
fn send(
req: Self::Request,
) -> impl Future<Output = Result<Self::Response, ServerFnError<CustErr>>> + Send;
}

#[cfg(feature = "browser")]
#[cfg(any(feature = "browser", doc))]
/// Implements [`Client`] for a `fetch` request in the browser.
pub mod browser {
use super::Client;
use crate::{
Expand All @@ -20,6 +30,7 @@ pub mod browser {
use send_wrapper::SendWrapper;
use std::future::Future;

/// Implements [`Client`] for a `fetch` request in the browser.
pub struct BrowserClient;

impl<CustErr> Client<CustErr> for BrowserClient {
Expand All @@ -42,7 +53,7 @@ pub mod browser {
}
}

#[cfg(feature = "reqwest")]
#[cfg(any(feature = "reqwest", doc))]
pub mod reqwest {
use super::Client;
use crate::{error::ServerFnError, request::reqwest::CLIENT};
Expand Down
55 changes: 49 additions & 6 deletions server_fn/src/codec/mod.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,47 @@
//! The serialization/deserialization process for server functions consists of a series of steps,
//! each of which is represented by a different trait:
//! 1. [`IntoReq`]: The client serializes the [`ServerFn`] argument type into an HTTP request.
//! 2. The [`Client`] sends the request to the server.
//! 3. [`FromReq`]: The server deserializes the HTTP request back into the [`ServerFn`] type.
//! 4. The server calls calls [`ServerFn::run_body`] on the data.
//! 5. [`IntoRes`]: The server serializes the [`ServerFn::Output`] type into an HTTP response.
//! 6. The server integration applies any middleware from [`ServerFn::middlewares`] and responds to the request.
//! 7. [`FromRes`]: The client deserializes the response back into the [`ServerFn::Output`] type.
//!
//! Rather than a limited number of encodings, this crate allows you to define server functions that
//! mix and match the input encoding and output encoding. To define a new encoding, you simply implement
//! an input combination ([`IntoReq`] and [`FromReq`]) and/or an output encoding ([`IntoRes`] and [`FromRes`]).
//! This genuinely is an and/or: while some encodings can be used for both input and output ([`Json`], [`Cbor`], [`Rkyv`]),
//! others can only be used for input ([`GetUrl`], [`MultipartData`]) or only output ([`ByteStream`], [`StreamingText`]).
#[cfg(feature = "cbor")]
mod cbor;
#[cfg(feature = "cbor")]
#[cfg(any(feature = "cbor", doc))]
pub use cbor::*;

#[cfg(feature = "json")]
mod json;
#[cfg(feature = "json")]
#[cfg(any(feature = "json", doc))]
pub use json::*;

#[cfg(feature = "serde-lite")]
mod serde_lite;
#[cfg(feature = "serde-lite")]
#[cfg(any(feature = "serde-lite", doc))]
pub use serde_lite::*;

#[cfg(feature = "rkyv")]
mod rkyv;
#[cfg(feature = "rkyv")]
#[cfg(any(feature = "rkyv", doc))]
pub use rkyv::*;

#[cfg(feature = "url")]
mod url;
#[cfg(feature = "url")]
#[cfg(any(feature = "url", doc))]
pub use url::*;

#[cfg(feature = "multipart")]
mod multipart;
#[cfg(feature = "multipart")]
#[cfg(any(feature = "multipart", doc))]
pub use multipart::*;

mod stream;
Expand All @@ -34,10 +50,37 @@ use futures::Future;
use http::Method;
pub use stream::*;

/// Deserializes an HTTP request into the data type.
///
/// Implementations use the methods of the [`Req`](crate::Req) trait to access whatever is
/// needed from the request.
///
/// For example, here’s the implementation for [`Json`].
///
/// ```rust
/// impl<CustErr, T, Request> FromReq<CustErr, Request, Json> for T
/// where
/// // require the Request implement `Req`
/// Request: Req<CustErr> + Send + 'static,
/// // require that the type can be deserialized with `serde`
/// T: DeserializeOwned,
/// {
/// async fn from_req(
/// req: Request,
/// ) -> Result<Self, ServerFnError<CustErr>> {
/// // try to convert the body of the request into a `String`
/// let string_data = req.try_into_string().await?;
/// // deserialize the data
/// serde_json::from_str::<Self>(&string_data)
/// .map_err(|e| ServerFnError::Args(e.to_string()))
/// }
/// }
/// ```
pub trait FromReq<CustErr, Request, Encoding>
where
Self: Sized,
{
/// Attempts to deserialize the request.
fn from_req(
req: Request,
) -> impl Future<Output = Result<Self, ServerFnError<CustErr>>> + Send;
Expand Down
Loading

0 comments on commit 013f5db

Please sign in to comment.