1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
use ;
use ;
use ;
use ;
/// 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> = Result;
/// 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_core::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,
/// )))
/// }
/// ```