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
This commit is contained in:
1 parent
67f717647f
commit
f610c6b8c1
20 files changed
+316
-96
No files matched your search
@@ -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"))
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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?)
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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()])
|
||||
}
|
||||
@@ -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))
|
||||
/// }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
Reference in new issue
Block a user