}
}
+
+/// The `ServerFnError` type is generic over a custom error type, which defaults to `NoCustomError`
+/// for backwards compatibility and to support the most common use case.
+///
+/// A custom error type should implement `FromStr` and `Display`, which allows it to be converted
+/// into and from a string easily to be sent over the network. It does *not* need to implement
+/// `Serialize` and `Deserialize`, although these can be used to generate the `FromStr`/`Display`
+/// implementations if you'd like. However, it's much lighter weight to use something like `strum`
+/// simply to generate those trait implementations.
+#[server]
+pub async fn ascii_uppercase(
+ text: String,
+) -> Result> {
+ if text.len() < 5 {
+ Err(InvalidArgument::TooShort.into())
+ } else if text.len() > 15 {
+ Err(InvalidArgument::TooLong.into())
+ } else if text.is_ascii() {
+ Ok(text.to_ascii_uppercase())
+ } else {
+ Err(InvalidArgument::NotAscii.into())
+ }
+}
+
+// The EnumString and Display derive macros are provided by strum
+#[derive(Debug, Clone, EnumString, Display)]
+pub enum InvalidArgument {
+ TooShort,
+ TooLong,
+ NotAscii,
+}
+
+#[component]
+pub fn CustomErrorTypes() -> impl IntoView {
+ let input_ref = NodeRef::::new();
+ let (result, set_result) = create_signal(None);
+
+ view! {
+
Using custom error types
+
+ "Server functions can use a custom error type that is preserved across the network boundary."
+
+
+ "Try typing a message that is between 5 and 15 characters of ASCII text below. Then try breaking \
+ the rules!"
+