diff --git a/leptos/src/lib.rs b/leptos/src/lib.rs index 3a314c7a4..a76c2fce7 100644 --- a/leptos/src/lib.rs +++ b/leptos/src/lib.rs @@ -182,7 +182,7 @@ pub use leptos_macro::{component, server, slot, view, Params}; pub use leptos_reactive::*; pub use leptos_server::{ self, create_action, create_multi_action, create_server_action, - create_server_multi_action, Action, MultiAction, ServerFn, ServerFnError, + create_server_multi_action, Action, MultiAction, ServerFn, ServerFnError, ServerFnErrorErr }; pub use server_fn::{self, ServerFn as _}; pub use typed_builder; diff --git a/leptos_dom/Cargo.toml b/leptos_dom/Cargo.toml index 43ddb35b2..2be5c473f 100644 --- a/leptos_dom/Cargo.toml +++ b/leptos_dom/Cargo.toml @@ -18,6 +18,7 @@ indexmap = "1.9" itertools = "0.10" js-sys = "0.3" leptos_reactive = { workspace = true } +server_fn = { workspace = true } once_cell = "1" pad-adapter = "0.1" paste = "1" diff --git a/leptos_dom/src/components/errors.rs b/leptos_dom/src/components/errors.rs index 1d7832de2..fa1a251e5 100644 --- a/leptos_dom/src/components/errors.rs +++ b/leptos_dom/src/components/errors.rs @@ -1,6 +1,7 @@ use crate::{HydrationCtx, IntoView}; use cfg_if::cfg_if; use leptos_reactive::{signal_prelude::*, use_context, RwSignal}; +use server_fn::{ServerFnError, ServerFnErrorErr}; use std::{borrow::Cow, collections::HashMap, error, fmt, ops, sync::Arc}; /// This is a result type into which any error can be converted, @@ -44,6 +45,12 @@ where } } +impl From for Error { + fn from(e: ServerFnError) -> Self { + Error(Arc::new(ServerFnErrorErr::from(e))) + } +} + /// A struct to hold all the possible errors that could be provided by child Views #[derive(Debug, Clone, Default)] #[repr(transparent)] @@ -164,6 +171,7 @@ where } } } + impl Errors { /// Returns `true` if there are no errors. #[inline(always)] diff --git a/leptos_server/src/lib.rs b/leptos_server/src/lib.rs index 5d6d0b31f..cf355e72b 100644 --- a/leptos_server/src/lib.rs +++ b/leptos_server/src/lib.rs @@ -116,7 +116,7 @@ //! your app is not available. use leptos_reactive::*; -pub use server_fn::{Encoding, Payload, ServerFnError}; +pub use server_fn::{Encoding, Payload, ServerFnError, ServerFnErrorErr}; mod action; mod multi_action; diff --git a/router/src/components/form.rs b/router/src/components/form.rs index 1be6c628e..1aaa73a5c 100644 --- a/router/src/components/form.rs +++ b/router/src/components/form.rs @@ -386,7 +386,7 @@ where let e = ServerFnError::Request(e.to_string()); value.try_set(Some(Err(e.clone()))); if let Some(error) = error { - error.try_set(Some(Box::new(e))); + error.try_set(Some(Box::new(ServerFnErrorErr::from(e)))); } }); }); @@ -406,7 +406,7 @@ where cx.batch(move || { value.try_set(Some(Err(e.clone()))); if let Some(error) = error { - error.try_set(Some(Box::new(e))); + error.try_set(Some(Box::new(ServerFnErrorErr::from(e)))); } }); } @@ -472,7 +472,7 @@ where error!("{e:?}"); if let Some(error) = error { error.try_set(Some(Box::new( - ServerFnError::Request( + ServerFnErrorErr::Request( e.as_string().unwrap_or_default(), ), ))); diff --git a/server_fn/src/lib.rs b/server_fn/src/lib.rs index 60c66d3a2..4a0ed3c02 100644 --- a/server_fn/src/lib.rs +++ b/server_fn/src/lib.rs @@ -452,8 +452,45 @@ where } /// Type for errors that can occur when using server functions. -#[derive(Error, Debug, Clone, Serialize, Deserialize)] +/// +/// Unlike [`ServerFnErrorErr`], this does not implement [`std::error::Error`]. +/// This means that other error types can easily be converted into it using the +/// `?` operator. +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum ServerFnError { + /// Error while trying to register the server function (only occurs in case of poisoned RwLock). + Registration(String), + /// Occurs on the client if there is a network error while trying to run function on server. + Request(String), + /// Occurs when there is an error while actually running the function on the server. + ServerError(String), + /// Occurs on the client if there is an error deserializing the server's response. + Deserialization(String), + /// Occurs on the client if there is an error serializing the server function arguments. + Serialization(String), + /// Occurs on the server if there is an error deserializing one of the arguments that's been sent. + Args(String), + /// Occurs on the server if there's a missing argument. + MissingArg(String), +} + +impl From for ServerFnError where E: std::error::Error { + fn from(e: E) -> Self { + ServerFnError::ServerError(e.to_string()) + } +} + +/// Type for errors that can occur when using server functions. +/// +/// Unlike [`ServerFnErrorErr`], this implements [`std::error::Error`]. This means +/// it can be used in situations in which the `Error` trait is required, but it’s +/// not possible to create a blanket implementation that converts other errors into +/// this type. +/// +/// [`ServerFnError`] and [`ServerFnErrorErr`] mutually implement [`From`], so +/// it is easy to convert between the two types. +#[derive(Error, Debug, Clone, Serialize, Deserialize)] +pub enum ServerFnErrorErr { /// Error while trying to register the server function (only occurs in case of poisoned RwLock). #[error("error while trying to register the server function: {0}")] Registration(String), @@ -477,6 +514,20 @@ pub enum ServerFnError { MissingArg(String), } +impl From for ServerFnErrorErr { + fn from(value: ServerFnError) -> Self { + match value { + ServerFnError::Registration(value) => ServerFnErrorErr::Registration(value), + ServerFnError::Request(value) => ServerFnErrorErr::Request(value), + ServerFnError::ServerError(value) => ServerFnErrorErr::ServerError(value), + ServerFnError::Deserialization(value) => ServerFnErrorErr::Deserialization(value), + ServerFnError::Serialization(value) => ServerFnErrorErr::Serialization(value), + ServerFnError::Args(value) => ServerFnErrorErr::Args(value), + ServerFnError::MissingArg(value) => ServerFnErrorErr::MissingArg(value), + } + } +} + /// Executes the HTTP call to call a server function from the client, given its URL and argument type. #[cfg(not(feature = "ssr"))] pub async fn call_server_fn(