mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Improve docs and debugging tools for server functions (closes #225)
This commit is contained in:
parent
8d14972808
commit
0da88f39cd
4 changed files with 72 additions and 2 deletions
|
@ -147,7 +147,9 @@ pub fn handle_server_fns() -> Route {
|
|||
}
|
||||
} else {
|
||||
HttpResponse::BadRequest()
|
||||
.body(format!("Could not find a server function at that route."))
|
||||
.body(format!("Could not find a server function at the route {:?}. \
|
||||
\n\nIt's likely that you need to call ServerFn::register() on the \
|
||||
server function type, somewhere in your `main` function.", req.path()))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -194,7 +194,9 @@ pub async fn handle_server_fns(
|
|||
Response::builder()
|
||||
.status(StatusCode::BAD_REQUEST)
|
||||
.body(Full::from(
|
||||
"Could not find a server function at that route.".to_string(),
|
||||
format!("Could not find a server function at the route {:?}. \
|
||||
\n\nIt's likely that you need to call ServerFn::register() on the \
|
||||
server function type, somewhere in your `main` function.", fn_name)
|
||||
))
|
||||
}
|
||||
.expect("could not build Response");
|
||||
|
|
|
@ -413,6 +413,55 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
|||
.into()
|
||||
}
|
||||
|
||||
/// Declares that a function is a [server function](leptos_server). This means that
|
||||
/// its body will only run on the server, i.e., when the `ssr` feature is enabled.
|
||||
///
|
||||
/// If you call a server function from the client (i.e., when the `csr` or `hydrate` features
|
||||
/// are enabled), it will instead make a network request to the server.
|
||||
///
|
||||
/// You can specify one, two, or three arguments to the server function:
|
||||
/// 1. **Required**: A type name that will be used to identify and register the server function
|
||||
/// (e.g., `MyServerFn`).
|
||||
/// 2. *Optional*: A URL prefix at which the function will be mounted when it’s registered
|
||||
/// (e.g., `"/api"`). Defaults to `"/"`.
|
||||
/// 3. *Optional*: either `"Cbor"` (specifying that it should use the binary `cbor` format for
|
||||
/// serialization) or `"Url"` (specifying that it should be use a URL-encoded form-data string).
|
||||
/// Defaults to `"Url"`. If you want to use this server function to power an
|
||||
/// [ActionForm](leptos_router::ActionForm) the encoding must be `"Url"`.
|
||||
///
|
||||
/// The server function itself can take any number of arguments, each of which should be serializable
|
||||
/// and deserializable with `serde`. Optionally, its first argument can be a Leptos [Scope](leptos::Scope),
|
||||
/// which will be injected *on the server side.* This can be used to inject the raw HTTP request or other
|
||||
/// server-side context into the server function.
|
||||
///
|
||||
/// ```
|
||||
/// # use leptos::*; use serde::{Serialize, Deserialize};
|
||||
/// # #[derive(Serialize, Deserialize)]
|
||||
/// # pub struct Post { }
|
||||
/// #[server(ReadPosts, "/api")]
|
||||
/// pub async fn read_posts(how_many: u8, query: String) -> Result<Vec<Post>, ServerFnError> {
|
||||
/// // do some work on the server to access the database
|
||||
/// todo!()
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note the following:
|
||||
/// - You must **register** the server function by calling `T::register()` somewhere in your main function.
|
||||
/// - **Server functions must be `async`.** Even if the work being done inside the function body
|
||||
/// can run synchronously on the server, from the client’s perspective it involves an asynchronous
|
||||
/// function call.
|
||||
/// - **Server functions must return `Result<T, ServerFnError>`.** Even if the work being done
|
||||
/// inside the function body can’t fail, the processes of serialization/deserialization and the
|
||||
/// network call are fallible.
|
||||
/// - **Return types must be [Serializable](leptos_reactive::Serializable).**
|
||||
/// This should be fairly obvious: we have to serialize arguments to send them to the server, and we
|
||||
/// need to deserialize the result to return it to the client.
|
||||
/// - **Arguments must be implement [serde::Serialize].** They are serialized as an `application/x-www-form-urlencoded`
|
||||
/// form data using [`serde_urlencoded`](https://docs.rs/serde_urlencoded/latest/serde_urlencoded/) or as `application/cbor`
|
||||
/// using [`cbor`](https://docs.rs/cbor/latest/cbor/).
|
||||
/// - **The [Scope](leptos_reactive::Scope) comes from the server.** Optionally, the first argument of a server function
|
||||
/// can be a Leptos [Scope](leptos_reactive::Scope). This scope can be used to inject dependencies like the HTTP request
|
||||
/// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client.
|
||||
#[proc_macro_attribute]
|
||||
pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
match server_macro_impl(args, s.into()) {
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
//! indicate that it should only run on the server (i.e., when you have an `ssr` feature in your
|
||||
//! crate that is enabled).
|
||||
//!
|
||||
//! **Important**: All server functions must be registered by calling [ServerFn::register]
|
||||
//! somewhere within your `main` function.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # use leptos::*;
|
||||
//! #[server(ReadFromDB)]
|
||||
|
@ -47,6 +50,11 @@
|
|||
//! log::debug!("posts = {posts{:#?}");
|
||||
//! })
|
||||
//! # });
|
||||
//!
|
||||
//! // make sure you've registered it somewhere in main
|
||||
//! fn main() {
|
||||
//! _ = ReadFromDB::register();
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! If you call this function from the client, it will serialize the function arguments and `POST`
|
||||
|
@ -165,6 +173,15 @@ pub fn server_fn_by_path(path: &str) -> Option<Arc<ServerFnTraitObj>> {
|
|||
.and_then(|fns| fns.get(path).cloned())
|
||||
}
|
||||
|
||||
/// Returns the set of currently-registered server function paths, for debugging purposes.
|
||||
#[cfg(any(feature = "ssr", doc))]
|
||||
pub fn server_fns_by_path() -> Vec<&'static str> {
|
||||
REGISTERED_SERVER_FUNCTIONS
|
||||
.read()
|
||||
.map(|vals| vals.keys().copied().collect())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Holds the current options for encoding types.
|
||||
/// More could be added, but they need to be serde
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
|
Loading…
Reference in a new issue