Browse Source

Implement Into<CaptureError> for the default server function error type (#4205)

* implement Into<CaptureError> for the server function error type

* document the server function error type

* fix tests
Evan Almloff 6 days ago
parent
commit
f610c6b8c1

+ 1 - 1
examples/fullstack-auth/src/auth.rs

@@ -196,7 +196,7 @@ pub async fn connect_to_database() -> SqlitePool {
 pub type Session =
     axum_session_auth::AuthSession<crate::auth::User, i64, SessionSqlitePool, sqlx::SqlitePool>;
 
-pub async fn get_session() -> Result<Session, ServerFnError> {
+pub async fn get_session() -> ServerFnResult<Session> {
     extract::<Session, _>()
         .await
         .map_err(|_| ServerFnError::new("AuthSessionLayer was not found"))

+ 11 - 10
examples/fullstack-auth/src/main.rs

@@ -75,7 +75,8 @@ fn app() -> Element {
         div {
             button { onclick: move |_| {
                     async move {
-                        login().await.unwrap();
+                        login().await?;
+                        Ok(())
                     }
                 },
                 "Login Test User"
@@ -84,9 +85,9 @@ fn app() -> Element {
         div {
             button {
                 onclick: move |_| async move {
-                    if let Ok(data) = get_user_name().await {
-                        user_name.set(data);
-                    }
+                    let data = get_user_name().await?;
+                    user_name.set(data);
+                    Ok(())
                 },
                 "Get User Name"
             }
@@ -95,9 +96,9 @@ fn app() -> Element {
         div {
             button {
                 onclick: move |_| async move {
-                    if let Ok(data) = get_permissions().await {
-                        permissions.set(data);
-                    }
+                    let data = get_permissions().await?;
+                    permissions.set(data);
+                    Ok(())
                 },
                 "Get Permissions"
             }
@@ -107,20 +108,20 @@ fn app() -> Element {
 }
 
 #[server]
-pub async fn get_user_name() -> Result<String, ServerFnError> {
+pub async fn get_user_name() -> ServerFnResult<String> {
     let auth = auth::get_session().await?;
     Ok(auth.current_user.unwrap().username.to_string())
 }
 
 #[server]
-pub async fn login() -> Result<(), ServerFnError> {
+pub async fn login() -> ServerFnResult {
     let auth = auth::get_session().await?;
     auth.login_user(2);
     Ok(())
 }
 
 #[server]
-pub async fn get_permissions() -> Result<String, ServerFnError> {
+pub async fn get_permissions() -> ServerFnResult<String> {
     let method: axum::http::Method = extract().await?;
     let auth = auth::get_session().await?;
     let current_user = auth.current_user.clone().unwrap_or_default();

+ 9 - 9
examples/fullstack-desktop/src/main.rs

@@ -18,11 +18,11 @@ pub fn app() -> Element {
         button { onclick: move |_| count -= 1, "Down low!" }
         button {
             onclick: move |_| async move {
-                if let Ok(data) = get_server_data().await {
-                    println!("Client received: {}", data);
-                    text.set(data.clone());
-                    post_server_data(data).await.unwrap();
-                }
+                let data = get_server_data().await?;
+                println!("Client received: {}", data);
+                text.set(data.clone());
+                post_server_data(data).await?;
+                Ok(())
             },
             "Run a server function"
         }
@@ -30,14 +30,14 @@ pub fn app() -> Element {
     }
 }
 
-#[server(PostServerData)]
-async fn post_server_data(data: String) -> Result<(), ServerFnError> {
+#[server]
+async fn post_server_data(data: String) -> ServerFnResult {
     println!("Server received: {}", data);
 
     Ok(())
 }
 
-#[server(GetServerData)]
-async fn get_server_data() -> Result<String, ServerFnError> {
+#[server]
+async fn get_server_data() -> ServerFnResult<String> {
     Ok("Hello from the server!".to_string())
 }

+ 7 - 7
examples/fullstack-hello-world/src/main.rs

@@ -20,11 +20,11 @@ fn app() -> Element {
         button { onclick: move |_| count -= 1, "Down low!" }
         button {
             onclick: move |_| async move {
-                if let Ok(data) = get_server_data().await {
-                    println!("Client received: {}", data);
-                    text.set(data.clone());
-                    post_server_data(data).await.unwrap();
-                }
+                let data = get_server_data().await?;
+                println!("Client received: {}", data);
+                text.set(data.clone());
+                post_server_data(data).await?;
+                Ok(())
             },
             "Run a server function!"
         }
@@ -33,14 +33,14 @@ fn app() -> Element {
 }
 
 #[server]
-async fn post_server_data(data: String) -> Result<(), ServerFnError> {
+async fn post_server_data(data: String) -> ServerFnResult {
     println!("Server received: {}", data);
 
     Ok(())
 }
 
 #[server]
-async fn get_server_data() -> Result<String, ServerFnError> {
+async fn get_server_data() -> ServerFnResult<String> {
     Ok(reqwest::get("https://httpbin.org/ip").await?.text().await?)
 }
 

+ 17 - 17
examples/fullstack-router/src/main.rs

@@ -52,34 +52,34 @@ fn Home() -> Element {
     let mut text = use_signal(|| "...".to_string());
 
     rsx! {
-    Link { to: Route::Blog { id: count() }, "Go to blog" }
-    div {
-        h1 { "High-Five counter: {count}" }
-        button { onclick: move |_| count += 1, "Up high!" }
-        button { onclick: move |_| count -= 1, "Down low!" }
-        button {
-            onclick: move |_| async move {
-                if let Ok(data) = get_server_data().await {
+        Link { to: Route::Blog { id: count() }, "Go to blog" }
+        div {
+            h1 { "High-Five counter: {count}" }
+            button { onclick: move |_| count += 1, "Up high!" }
+            button { onclick: move |_| count -= 1, "Down low!" }
+            button {
+                onclick: move |_| async move {
+                    let data = get_server_data().await?;
                     println!("Client received: {}", data);
                     text.set(data.clone());
-                    post_server_data(data).await.unwrap();
-                }
-            },
-            "Run server function!"
+                    post_server_data(data).await?;
+                    Ok(())
+                },
+                "Run server function!"
+            }
+            "Server said: {text}"
         }
-        "Server said: {text}"
-                    }
-                }
+    }
 }
 
 #[server(PostServerData)]
-async fn post_server_data(data: String) -> Result<(), ServerFnError> {
+async fn post_server_data(data: String) -> ServerFnResult {
     println!("Server received: {}", data);
 
     Ok(())
 }
 
 #[server(GetServerData)]
-async fn get_server_data() -> Result<String, ServerFnError> {
+async fn get_server_data() -> ServerFnResult<String> {
     Ok("Hello from the server!".to_string())
 }

+ 7 - 7
examples/fullstack-streaming/src/main.rs

@@ -9,13 +9,13 @@ fn app() -> Element {
         button {
             onclick: move |_| async move {
                 response.write().clear();
-                if let Ok(stream) = test_stream().await {
-                    response.write().push_str("Stream started\n");
-                    let mut stream = stream.into_inner();
-                    while let Some(Ok(text)) = stream.next().await {
-                        response.write().push_str(&text);
-                    }
+                let stream = test_stream().await?;
+                response.write().push_str("Stream started\n");
+                let mut stream = stream.into_inner();
+                while let Some(Ok(text)) = stream.next().await {
+                    response.write().push_str(&text);
                 }
+                Ok(())
             },
             "Start stream"
         }
@@ -24,7 +24,7 @@ fn app() -> Element {
 }
 
 #[server(output = StreamingText)]
-pub async fn test_stream() -> Result<TextStream, ServerFnError> {
+pub async fn test_stream() -> ServerFnResult<TextStream<ServerFnError>> {
     let (tx, rx) = futures::channel::mpsc::unbounded();
     tokio::spawn(async move {
         loop {

+ 1 - 1
examples/fullstack-websockets/src/main.rs

@@ -45,7 +45,7 @@ fn app() -> Element {
 #[server(protocol = Websocket<JsonEncoding, JsonEncoding>)]
 async fn uppercase_ws(
     input: BoxedStream<String, ServerFnError>,
-) -> Result<BoxedStream<String, ServerFnError>, ServerFnError> {
+) -> ServerFnResult<BoxedStream<String, ServerFnError>> {
     let mut input = input;
 
     // Create a channel with the output of the websocket

+ 2 - 2
packages/fullstack/README.md

@@ -58,7 +58,7 @@ fn App() -> Element {
 }
 
 #[server]
-async fn get_meaning(of: String) -> Result<Option<u32>, ServerFnError> {
+async fn get_meaning(of: String) -> ServerFnResult<Option<u32>> {
     Ok(of.contains("life").then(|| 42))
 }
 ```
@@ -131,7 +131,7 @@ fn App() -> Element {
 }
 
 #[server]
-async fn get_meaning(of: String) -> Result<Option<u32>, ServerFnError> {
+async fn get_meaning(of: String) -> ServerFnResult<Option<u32>> {
     Ok(of.contains("life").then(|| 42))
 }
 ```

+ 1 - 1
packages/fullstack/docs/request_origin.md

@@ -23,7 +23,7 @@ fn PrintHtmlRequestInfo() -> Element {
 ```rust
 # use dioxus::prelude::*;
 #[server]
-async fn read_headers() -> Result<(), ServerFnError> {
+async fn read_headers() -> ServerFnResult {
     // Since we are calling this from a server function, the server context that is may be from the
     // initial request or a request from the client
     let context = server_context();

+ 221 - 0
packages/fullstack/src/error.rs

@@ -0,0 +1,221 @@
+use std::{
+    error::Error,
+    fmt::{Debug, Display},
+    str::FromStr,
+};
+
+use dioxus_lib::prelude::{dioxus_core::CapturedError, RenderError};
+use serde::{de::DeserializeOwned, Serialize};
+use server_fn::{
+    codec::JsonEncoding,
+    error::{FromServerFnError, ServerFnErrorErr},
+};
+
+/// A default result type for server functions, which can either be successful or contain an error. The [`ServerFnResult`] type
+/// is a convenient alias for a `Result` type that uses [`ServerFnError`] as the error type.
+///
+/// # Example
+/// ```rust
+/// use dioxus::prelude::*;
+///
+/// #[server]
+/// async fn parse_number(number: String) -> ServerFnResult<f32> {
+///     let parsed_number: f32 = number.parse()?;
+///     Ok(parsed_number)
+/// }
+/// ```
+pub type ServerFnResult<T = (), E = String> = std::result::Result<T, ServerFnError<E>>;
+
+/// An error type for server functions. This may either be an error that occurred while running the server
+/// function logic, or an error that occurred while communicating with the server inside the server function crate.
+///
+/// ## Usage
+///
+/// You can use the [`ServerFnError`] type in the Error type of your server function result or use the [`ServerFnResult`]
+/// type as the return type of your server function. When you call the server function, you can handle the error directly
+/// or convert it into a [`CapturedError`] to throw into the nearest [`ErrorBoundary`](dioxus_lib::prelude::ErrorBoundary).
+///
+/// ```rust
+/// use dioxus::prelude::*;
+///
+/// #[server]
+/// async fn parse_number(number: String) -> ServerFnResult<f32> {
+///     // You can convert any error type into the `ServerFnError` with the `?` operator
+///     let parsed_number: f32 = number.parse()?;
+///     Ok(parsed_number)
+/// }
+///
+/// #[component]
+/// fn ParseNumberServer() -> Element {
+///     let mut number = use_signal(|| "42".to_string());
+///     let mut parsed = use_signal(|| None);
+///
+///     rsx! {
+///         input {
+///             value: "{number}",
+///             oninput: move |e| number.set(e.value()),
+///         }
+///         button {
+///             onclick: move |_| async move {
+///                 // Call the server function to parse the number
+///                 // If the result is Ok, continue running the closure, otherwise bubble up the
+///                 // error to the nearest error boundary with `?`
+///                 let result = parse_number(number()).await?;
+///                 parsed.set(Some(result));
+///                 Ok(())
+///             },
+///             "Parse Number"
+///         }
+///         if let Some(value) = parsed() {
+///             p { "Parsed number: {value}" }
+///         } else {
+///             p { "No number parsed yet." }
+///         }
+///     }
+/// }
+/// ```
+///
+/// ## Differences from [`CapturedError`]
+///
+/// Both this error type and [`CapturedError`] can be used to represent boxed errors in dioxus. However, this error type
+/// is more strict about the kinds of errors it can represent. [`CapturedError`] can represent any error that implements
+/// the [`Error`] trait or can be converted to a string. [`CapturedError`] holds onto the type information of the error
+/// and lets you downcast the error to its original type.
+///
+/// [`ServerFnError`] represents server function errors as [`String`]s by default without any additional type information.
+/// This makes it easy to serialize the error to JSON and send it over the wire, but it means that you can't get the
+/// original type information of the error back. If you need to preserve the type information of the error, you can use a
+/// [custom error variant](#custom-error-variants) that holds onto the type information.
+///
+/// ## Custom error variants
+///
+/// The [`ServerFnError`] type accepts a generic type parameter `T` that is used to represent the error type used for server
+/// functions. If you need to keep the type information of your error, you can create a custom error variant that implements
+/// [`Serialize`] and [`DeserializeOwned`]. This allows you to serialize the error to JSON and send it over the wire,
+/// while still preserving the type information.
+///
+/// ```rust
+/// use dioxus::prelude::*;
+/// use serde::{Deserialize, Serialize};
+/// use std::fmt::Debug;
+///
+/// #[derive(Clone, Debug, Serialize, Deserialize)]
+/// pub struct MyCustomError {
+///     message: String,
+///     code: u32,
+/// }
+///
+/// impl MyCustomError {
+///     pub fn new(message: String, code: u32) -> Self {
+///         Self { message, code }
+///     }
+/// }
+///
+/// #[server]
+/// async fn server_function() -> ServerFnResult<String, MyCustomError> {
+///     // Return your custom error
+///     Err(ServerFnError::ServerError(MyCustomError::new(
+///         "An error occurred".to_string(),
+///         404,
+///     )))
+/// }
+/// ```
+#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
+pub enum ServerFnError<T = String> {
+    /// An error running the server function
+    ServerError(T),
+
+    /// An error communicating with the server
+    CommunicationError(ServerFnErrorErr),
+}
+
+impl ServerFnError {
+    /// Creates a new `ServerFnError` from something that implements `ToString`.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use dioxus::prelude::*;
+    ///
+    /// #[server]
+    /// async fn server_function() -> ServerFnResult<String, MyCustomError> {
+    ///     // Return your custom error
+    ///     Err(ServerFnError::new("Something went wrong"))
+    /// }
+    /// ```
+    pub fn new(error: impl ToString) -> Self {
+        Self::ServerError(error.to_string())
+    }
+}
+
+impl<T> ServerFnError<T> {
+    /// Returns true if the error is a server error
+    pub fn is_server_error(&self) -> bool {
+        matches!(self, ServerFnError::ServerError(_))
+    }
+
+    /// Returns true if the error is a communication error
+    pub fn is_communication_error(&self) -> bool {
+        matches!(self, ServerFnError::CommunicationError(_))
+    }
+
+    /// Returns a reference to the server error if it is a server error
+    /// or `None` if it is a communication error.
+    pub fn server_error(&self) -> Option<&T> {
+        match self {
+            ServerFnError::ServerError(err) => Some(err),
+            ServerFnError::CommunicationError(_) => None,
+        }
+    }
+
+    /// Returns a reference to the communication error if it is a communication error
+    /// or `None` if it is a server error.
+    pub fn communication_error(&self) -> Option<&ServerFnErrorErr> {
+        match self {
+            ServerFnError::ServerError(_) => None,
+            ServerFnError::CommunicationError(err) => Some(err),
+        }
+    }
+}
+
+impl<T: Serialize + DeserializeOwned + Debug + 'static> FromServerFnError for ServerFnError<T> {
+    type Encoder = JsonEncoding;
+
+    fn from_server_fn_error(err: ServerFnErrorErr) -> Self {
+        Self::CommunicationError(err)
+    }
+}
+
+impl<T: FromStr> FromStr for ServerFnError<T> {
+    type Err = <T as FromStr>::Err;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        std::result::Result::Ok(Self::ServerError(T::from_str(s)?))
+    }
+}
+
+impl<T: Display> Display for ServerFnError<T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            ServerFnError::ServerError(err) => write!(f, "Server error: {}", err),
+            ServerFnError::CommunicationError(err) => write!(f, "Communication error: {}", err),
+        }
+    }
+}
+
+impl From<ServerFnError> for CapturedError {
+    fn from(error: ServerFnError) -> Self {
+        Self::from_display(error)
+    }
+}
+
+impl From<ServerFnError> for RenderError {
+    fn from(error: ServerFnError) -> Self {
+        RenderError::Aborted(CapturedError::from(error))
+    }
+}
+
+impl<E: Error> From<E> for ServerFnError {
+    fn from(error: E) -> Self {
+        Self::ServerError(error.to_string())
+    }
+}

+ 5 - 2
packages/fullstack/src/lib.rs

@@ -1,12 +1,14 @@
 #![doc = include_str!("../README.md")]
 #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
 #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
-#![deny(missing_docs)]
+#![warn(missing_docs)]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 
 #[cfg(all(feature = "web", feature = "document"))]
 mod web;
 
+mod error;
+
 #[cfg(all(feature = "web", feature = "document"))]
 pub use web::FullstackWebDocument;
 
@@ -19,8 +21,9 @@ pub use dioxus_fullstack_hooks::history::FullstackHistory;
 pub mod prelude {
     pub use dioxus_fullstack_hooks::prelude::*;
 
+    pub use crate::error::{ServerFnError, ServerFnResult};
     pub use dioxus_server_macro::*;
-    pub use server_fn::{self, ServerFn as _, ServerFnError};
+    pub use server_fn::{self, ServerFn as _};
 
     #[cfg(feature = "server")]
     pub use dioxus_server::prelude::*;

+ 1 - 1
packages/playwright-tests/default-features-disabled/src/main.rs

@@ -44,6 +44,6 @@ fn current_platform_features() -> Vec<String> {
 }
 
 #[server]
-async fn get_server_features() -> Result<Vec<String>, ServerFnError> {
+async fn get_server_features() -> ServerFnResult<Vec<String>> {
     Ok(current_platform_features())
 }

+ 9 - 14
packages/playwright-tests/fullstack/src/main.rs

@@ -5,12 +5,9 @@
 // - Hydration
 
 #![allow(non_snake_case)]
-use dioxus::{
-    prelude::{
-        server_fn::{codec::JsonEncoding, BoxedStream, Websocket},
-        *,
-    },
-    CapturedError,
+use dioxus::prelude::{
+    server_fn::{codec::JsonEncoding, BoxedStream, Websocket},
+    *,
 };
 use futures::{channel::mpsc, SinkExt, StreamExt};
 
@@ -85,7 +82,7 @@ async fn assert_server_context_provided() {
 }
 
 #[server(PostServerData)]
-async fn post_server_data(data: String) -> Result<(), ServerFnError> {
+async fn post_server_data(data: String) -> ServerFnResult {
     assert_server_context_provided().await;
     println!("Server received: {}", data);
 
@@ -93,7 +90,7 @@ async fn post_server_data(data: String) -> Result<(), ServerFnError> {
 }
 
 #[server(GetServerData)]
-async fn get_server_data() -> Result<String, ServerFnError> {
+async fn get_server_data() -> ServerFnResult<String> {
     assert_server_context_provided().await;
     Ok("Hello from the server!".to_string())
 }
@@ -101,14 +98,14 @@ async fn get_server_data() -> Result<String, ServerFnError> {
 // Make sure the default codec work with empty data structures
 // Regression test for https://github.com/DioxusLabs/dioxus/issues/2628
 #[server]
-async fn get_server_data_empty_vec(empty_vec: Vec<String>) -> Result<Vec<String>, ServerFnError> {
+async fn get_server_data_empty_vec(empty_vec: Vec<String>) -> ServerFnResult<Vec<String>> {
     assert_server_context_provided().await;
     assert!(empty_vec.is_empty());
     Ok(Vec::new())
 }
 
 #[server]
-async fn server_error() -> Result<String, ServerFnError> {
+async fn server_error() -> ServerFnResult<String> {
     assert_server_context_provided().await;
     tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
     Err(ServerFnError::new("the server threw an error!"))
@@ -142,9 +139,7 @@ fn Errors() -> Element {
 
 #[component]
 pub fn ThrowsError() -> Element {
-    use_server_future(server_error)?
-        .unwrap()
-        .map_err(CapturedError::from_display)?;
+    use_server_future(server_error)?.unwrap()?;
     rsx! {
         "success"
     }
@@ -187,7 +182,7 @@ fn Assets() -> Element {
 #[server(protocol = Websocket<JsonEncoding, JsonEncoding>)]
 async fn echo_ws(
     input: BoxedStream<String, ServerFnError>,
-) -> Result<BoxedStream<String, ServerFnError>, ServerFnError> {
+) -> ServerFnResult<BoxedStream<String, ServerFnError>> {
     let mut input = input;
 
     let (mut tx, rx) = mpsc::channel(1);

+ 1 - 1
packages/playwright-tests/nested-suspense/src/lib.rs

@@ -83,7 +83,7 @@ pub struct Content {
 }
 
 #[server]
-async fn server_content(id: usize) -> Result<Content, ServerFnError> {
+async fn server_content(id: usize) -> ServerFnResult<Content> {
     let content_tree = [
         Content {
             title: "The robot says hello world".to_string(),

+ 1 - 1
packages/playwright-tests/nested-suspense/src/ssg.rs

@@ -25,6 +25,6 @@ fn main() {
 }
 
 #[server(endpoint = "static_routes")]
-async fn static_routes() -> Result<Vec<String>, ServerFnError> {
+async fn static_routes() -> ServerFnResult<Vec<String>> {
     Ok(vec!["/".to_string()])
 }

+ 6 - 6
packages/server-macro/src/lib.rs

@@ -18,11 +18,11 @@ use syn::{__private::ToTokens, parse_quote};
 /// # use dioxus::prelude::*;
 /// # #[derive(serde::Deserialize, serde::Serialize)]
 /// # pub struct BlogPost;
-/// # async fn load_posts(category: &str) -> Result<Vec<BlogPost>, ServerFnError> { unimplemented!() }
+/// # async fn load_posts(category: &str) -> ServerFnResult<Vec<BlogPost>> { unimplemented!() }
 /// #[server]
 /// pub async fn blog_posts(
 ///     category: String,
-/// ) -> Result<Vec<BlogPost>, ServerFnError> {
+/// ) -> ServerFnResult<Vec<BlogPost>> {
 ///     let posts = load_posts(&category).await?;
 ///     // maybe do some other work
 ///     Ok(posts)
@@ -118,7 +118,7 @@ use syn::{__private::ToTokens, parse_quote};
 ///   input = Cbor,
 ///   output = Json
 /// )]
-/// pub async fn my_wacky_server_fn(input: Vec<String>) -> Result<usize, ServerFnError> {
+/// pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<usize> {
 ///   unimplemented!()
 /// }
 ///
@@ -155,7 +155,7 @@ use syn::{__private::ToTokens, parse_quote};
 /// #[server]
 /// // The TraceLayer will log all requests to the console
 /// #[middleware(tower_http::timeout::TimeoutLayer::new(std::time::Duration::from_secs(5)))]
-/// pub async fn my_wacky_server_fn(input: Vec<String>) -> Result<usize, ServerFnError> {
+/// pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<usize> {
 ///     unimplemented!()
 /// }
 /// ```
@@ -171,7 +171,7 @@ use syn::{__private::ToTokens, parse_quote};
 /// ```rust,ignore
 /// # use dioxus::prelude::*;
 /// #[server]
-/// pub async fn my_wacky_server_fn(input: Vec<String>) -> Result<String, ServerFnError> {
+/// pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<String> {
 ///     let headers: axum::http::header::HeaderMap = extract().await?;
 ///     Ok(format!("The server got a request with headers: {:?}", headers))
 /// }
@@ -198,7 +198,7 @@ use syn::{__private::ToTokens, parse_quote};
 /// }
 ///
 /// #[server]
-/// pub async fn my_wacky_server_fn(input: Vec<String>) -> Result<String, ServerFnError> {
+/// pub async fn my_wacky_server_fn(input: Vec<String>) -> ServerFnResult<String> {
 ///     let FromContext(pool): FromContext<DatabasePool> = extract().await?;
 ///     Ok(format!("The server read {:?} from the shared context", pool))
 /// }

+ 1 - 1
packages/server/docs/request_origin.md

@@ -23,7 +23,7 @@ fn PrintHtmlRequestInfo() -> Element {
 ```rust
 # use dioxus::prelude::*;
 #[server]
-async fn read_headers() -> Result<(), ServerFnError> {
+async fn read_headers() -> ServerFnResult {
     // Since we are calling this from a server function, the server context that is may be from the
     // initial request or a request from the client
     let context = server_context();

+ 3 - 3
packages/server/src/config.rs

@@ -157,7 +157,7 @@ impl ServeConfigBuilder {
     /// }
     ///
     /// #[server]
-    /// async fn read_context() -> Result<u32, ServerFnError> {
+    /// async fn read_context() -> ServerFnResult<u32> {
     ///     // You can extract values from the server context with the `extract` function
     ///     let FromContext(value) = extract().await?;
     ///     Ok(value)
@@ -224,7 +224,7 @@ impl ServeConfigBuilder {
     /// }
     ///
     /// #[server]
-    /// async fn read_context() -> Result<u32, ServerFnError> {
+    /// async fn read_context() -> ServerFnResult<u32> {
     ///     // You can extract values from the server context with the `extract` function
     ///     let FromContext(value) = extract().await?;
     ///     Ok(value)
@@ -284,7 +284,7 @@ impl ServeConfigBuilder {
     /// }
     ///
     /// #[server]
-    /// async fn read_context() -> Result<u32, ServerFnError> {
+    /// async fn read_context() -> ServerFnResult<u32> {
     ///     // You can extract values from the server context with the `extract` function
     ///     let FromContext(value) = extract().await?;
     ///     Ok(value)

+ 11 - 11
packages/server/src/context.rs

@@ -48,7 +48,7 @@ impl AtomicResponsePartsModified {
 /// ```rust, no_run
 /// # use dioxus::prelude::*;
 /// #[server]
-/// async fn read_headers() -> Result<(), ServerFnError> {
+/// async fn read_headers() -> ServerFnResult {
 ///     let server_context = server_context();
 ///     let headers: http::HeaderMap = server_context.extract().await?;
 ///     println!("{:?}", headers);
@@ -141,7 +141,7 @@ mod server_fn_impl {
         ///     .launch(app);
         ///
         /// #[server]
-        /// async fn read_context() -> Result<u32, ServerFnError> {
+        /// async fn read_context() -> ServerFnResult<u32> {
         ///     // You can extract values from the server context with the `extract` function
         ///     let FromContext(value) = extract().await?;
         ///     Ok(value)
@@ -201,7 +201,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn set_headers() -> Result<(), ServerFnError> {
+        /// async fn set_headers() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     let response_parts = server_context.response_parts();
         ///     let cookies = response_parts
@@ -225,7 +225,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn set_headers() -> Result<(), ServerFnError> {
+        /// async fn set_headers() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     server_context.headers_mut()
         ///         .insert("Cookie", http::HeaderValue::from_static("dioxus=fullstack"));
@@ -247,7 +247,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn set_status() -> Result<(), ServerFnError> {
+        /// async fn set_status() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     *server_context.status_mut() = http::StatusCode::INTERNAL_SERVER_ERROR;
         ///     Ok(())
@@ -268,7 +268,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn set_version() -> Result<(), ServerFnError> {
+        /// async fn set_version() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     *server_context.version_mut() = http::Version::HTTP_2;
         ///     Ok(())
@@ -289,7 +289,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn set_version() -> Result<(), ServerFnError> {
+        /// async fn set_version() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     *server_context.version_mut() = http::Version::HTTP_2;
         ///     Ok(())
@@ -323,7 +323,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn read_headers() -> Result<(), ServerFnError> {
+        /// async fn read_headers() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     let request_parts = server_context.request_parts();
         ///     let id: &i32 = request_parts
@@ -347,7 +347,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn read_headers() -> Result<(), ServerFnError> {
+        /// async fn read_headers() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     let id: i32 = server_context.request_parts_mut()
         ///         .extensions
@@ -370,7 +370,7 @@ mod server_fn_impl {
         /// ```rust, no_run
         /// # use dioxus::prelude::*;
         /// #[server]
-        /// async fn read_headers() -> Result<(), ServerFnError> {
+        /// async fn read_headers() -> ServerFnResult {
         ///     let server_context = server_context();
         ///     let headers: http::HeaderMap = server_context.extract().await?;
         ///     println!("{:?}", headers);
@@ -526,7 +526,7 @@ impl<T: 'static> std::error::Error for NotFoundInServerContext<T> {}
 ///     .launch(app);
 ///
 /// #[server]
-/// async fn read_context() -> Result<u32, ServerFnError> {
+/// async fn read_context() -> ServerFnResult<u32> {
 ///     // You can extract values from the server context with the `extract` function
 ///     let FromContext(value) = extract().await?;
 ///     Ok(value)

+ 1 - 1
packages/server/src/lib.rs

@@ -50,7 +50,7 @@
 //! }
 //!
 //! #[server(GetServerData)]
-//! async fn get_server_data() -> Result<String, ServerFnError> {
+//! async fn get_server_data() -> ServerFnResult<String> {
 //!     Ok("Hello from the server!".to_string())
 //! }
 //! ```