server_fn/
error.rs

1#![allow(deprecated)]
2
3use crate::{ContentType, Decodes, Encodes, Format, FormatType};
4use base64::{engine::general_purpose::URL_SAFE, Engine as _};
5use bytes::Bytes;
6use serde::{Deserialize, Serialize};
7use std::{
8    fmt::{self, Display, Write},
9    str::FromStr,
10};
11use throw_error::Error;
12use url::Url;
13
14/// A custom header that can be used to indicate a server function returned an error.
15pub const SERVER_FN_ERROR_HEADER: &str = "serverfnerror";
16
17impl From<ServerFnError> for Error {
18    fn from(e: ServerFnError) -> Self {
19        Error::from(ServerFnErrorWrapper(e))
20    }
21}
22
23/// An empty value indicating that there is no custom error type associated
24/// with this server function.
25#[derive(
26    Debug,
27    Deserialize,
28    Serialize,
29    PartialEq,
30    Eq,
31    Hash,
32    PartialOrd,
33    Ord,
34    Clone,
35    Copy,
36)]
37#[cfg_attr(
38    feature = "rkyv",
39    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
40)]
41#[deprecated(
42    since = "0.8.0",
43    note = "Now server_fn can return any error type other than ServerFnError, \
44            so the WrappedServerError variant will be removed in 0.9.0"
45)]
46pub struct NoCustomError;
47
48// Implement `Display` for `NoCustomError`
49impl fmt::Display for NoCustomError {
50    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51        write!(f, "Unit Type Displayed")
52    }
53}
54
55impl FromStr for NoCustomError {
56    type Err = ();
57
58    fn from_str(_s: &str) -> Result<Self, Self::Err> {
59        Ok(NoCustomError)
60    }
61}
62
63/// Wraps some error type, which may implement any of [`Error`](trait@std::error::Error), [`Clone`], or
64/// [`Display`].
65#[derive(Debug)]
66#[deprecated(
67    since = "0.8.0",
68    note = "Now server_fn can return any error type other than ServerFnError, \
69            so the WrappedServerError variant will be removed in 0.9.0"
70)]
71pub struct WrapError<T>(pub T);
72
73/// A helper macro to convert a variety of different types into `ServerFnError`.
74/// This should mostly be used if you are implementing `From<ServerFnError>` for `YourError`.
75#[macro_export]
76#[deprecated(
77    since = "0.8.0",
78    note = "Now server_fn can return any error type other than ServerFnError, \
79            so the WrappedServerError variant will be removed in 0.9.0"
80)]
81macro_rules! server_fn_error {
82    () => {{
83        use $crate::{ViaError, WrapError};
84        (&&&&&WrapError(())).to_server_error()
85    }};
86    ($err:expr) => {{
87        use $crate::error::{ViaError, WrapError};
88        match $err {
89            error => (&&&&&WrapError(error)).to_server_error(),
90        }
91    }};
92}
93
94/// This trait serves as the conversion method between a variety of types
95/// and [`ServerFnError`].
96#[deprecated(
97    since = "0.8.0",
98    note = "Now server_fn can return any error type other than ServerFnError, \
99            so users should place their custom error type instead of \
100            ServerFnError"
101)]
102pub trait ViaError<E> {
103    /// Converts something into an error.
104    fn to_server_error(&self) -> ServerFnError<E>;
105}
106
107// This impl should catch if you fed it a [`ServerFnError`] already.
108impl<E: ServerFnErrorKind + std::error::Error + Clone> ViaError<E>
109    for &&&&WrapError<ServerFnError<E>>
110{
111    fn to_server_error(&self) -> ServerFnError<E> {
112        self.0.clone()
113    }
114}
115
116// A type tag for ServerFnError so we can special case it
117#[deprecated]
118pub(crate) trait ServerFnErrorKind {}
119
120impl ServerFnErrorKind for ServerFnError {}
121
122// This impl should catch passing () or nothing to server_fn_error
123impl ViaError<NoCustomError> for &&&WrapError<()> {
124    fn to_server_error(&self) -> ServerFnError {
125        ServerFnError::WrappedServerError(NoCustomError)
126    }
127}
128
129// This impl will catch any type that implements any type that impls
130// Error and Clone, so that it can be wrapped into ServerFnError
131impl<E: std::error::Error + Clone> ViaError<E> for &&WrapError<E> {
132    fn to_server_error(&self) -> ServerFnError<E> {
133        ServerFnError::WrappedServerError(self.0.clone())
134    }
135}
136
137// If it doesn't impl Error, but does impl Display and Clone,
138// we can still wrap it in String form
139impl<E: Display + Clone> ViaError<E> for &WrapError<E> {
140    fn to_server_error(&self) -> ServerFnError<E> {
141        ServerFnError::ServerError(self.0.to_string())
142    }
143}
144
145// This is what happens if someone tries to pass in something that does
146// not meet the above criteria
147impl<E> ViaError<E> for WrapError<E> {
148    #[track_caller]
149    fn to_server_error(&self) -> ServerFnError<E> {
150        panic!(
151            "At {}, you call `to_server_error()` or use  `server_fn_error!` \
152             with a value that does not implement `Clone` and either `Error` \
153             or `Display`.",
154            std::panic::Location::caller()
155        );
156    }
157}
158
159/// A type that can be used as the return type of the server function for easy error conversion with `?` operator.
160/// This type can be replaced with any other error type that implements `FromServerFnError`.
161///
162/// Unlike [`ServerFnErrorErr`], this does not implement [`Error`](trait@std::error::Error).
163/// This means that other error types can easily be converted into it using the
164/// `?` operator.
165#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
166#[cfg_attr(
167    feature = "rkyv",
168    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
169)]
170pub enum ServerFnError<E = NoCustomError> {
171    #[deprecated(
172        since = "0.8.0",
173        note = "Now server_fn can return any error type other than \
174                ServerFnError, so users should place their custom error type \
175                instead of ServerFnError"
176    )]
177    /// A user-defined custom error type, which defaults to [`NoCustomError`].
178    WrappedServerError(E),
179    /// Error while trying to register the server function (only occurs in case of poisoned RwLock).
180    Registration(String),
181    /// Occurs on the client if there is a network error while trying to run function on server.
182    Request(String),
183    /// Occurs on the server if there is an error creating an HTTP response.
184    Response(String),
185    /// Occurs when there is an error while actually running the function on the server.
186    ServerError(String),
187    /// Occurs when there is an error while actually running the middleware on the server.
188    MiddlewareError(String),
189    /// Occurs on the client if there is an error deserializing the server's response.
190    Deserialization(String),
191    /// Occurs on the client if there is an error serializing the server function arguments.
192    Serialization(String),
193    /// Occurs on the server if there is an error deserializing one of the arguments that's been sent.
194    Args(String),
195    /// Occurs on the server if there's a missing argument.
196    MissingArg(String),
197}
198
199impl ServerFnError<NoCustomError> {
200    /// Constructs a new [`ServerFnError::ServerError`] from some other type.
201    pub fn new(msg: impl ToString) -> Self {
202        Self::ServerError(msg.to_string())
203    }
204}
205
206impl<CustErr> From<CustErr> for ServerFnError<CustErr> {
207    fn from(value: CustErr) -> Self {
208        ServerFnError::WrappedServerError(value)
209    }
210}
211
212impl<E: std::error::Error> From<E> for ServerFnError {
213    fn from(value: E) -> Self {
214        ServerFnError::ServerError(value.to_string())
215    }
216}
217
218impl<CustErr> Display for ServerFnError<CustErr>
219where
220    CustErr: Display,
221{
222    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223        write!(
224            f,
225            "{}",
226            match self {
227                ServerFnError::Registration(s) => format!(
228                    "error while trying to register the server function: {s}"
229                ),
230                ServerFnError::Request(s) => format!(
231                    "error reaching server to call server function: {s}"
232                ),
233                ServerFnError::ServerError(s) =>
234                    format!("error running server function: {s}"),
235                ServerFnError::MiddlewareError(s) =>
236                    format!("error running middleware: {s}"),
237                ServerFnError::Deserialization(s) =>
238                    format!("error deserializing server function results: {s}"),
239                ServerFnError::Serialization(s) =>
240                    format!("error serializing server function arguments: {s}"),
241                ServerFnError::Args(s) => format!(
242                    "error deserializing server function arguments: {s}"
243                ),
244                ServerFnError::MissingArg(s) => format!("missing argument {s}"),
245                ServerFnError::Response(s) =>
246                    format!("error generating HTTP response: {s}"),
247                ServerFnError::WrappedServerError(e) => format!("{e}"),
248            }
249        )
250    }
251}
252
253/// Serializes and deserializes JSON with [`serde_json`].
254pub struct ServerFnErrorEncoding;
255
256impl ContentType for ServerFnErrorEncoding {
257    const CONTENT_TYPE: &'static str = "text/plain";
258}
259
260impl FormatType for ServerFnErrorEncoding {
261    const FORMAT_TYPE: Format = Format::Text;
262}
263
264impl<CustErr> Encodes<ServerFnError<CustErr>> for ServerFnErrorEncoding
265where
266    CustErr: Display,
267{
268    type Error = std::fmt::Error;
269
270    fn encode(output: &ServerFnError<CustErr>) -> Result<Bytes, Self::Error> {
271        let mut buf = String::new();
272        let result = match output {
273            ServerFnError::WrappedServerError(e) => {
274                write!(&mut buf, "WrappedServerFn|{e}")
275            }
276            ServerFnError::Registration(e) => {
277                write!(&mut buf, "Registration|{e}")
278            }
279            ServerFnError::Request(e) => write!(&mut buf, "Request|{e}"),
280            ServerFnError::Response(e) => write!(&mut buf, "Response|{e}"),
281            ServerFnError::ServerError(e) => {
282                write!(&mut buf, "ServerError|{e}")
283            }
284            ServerFnError::MiddlewareError(e) => {
285                write!(&mut buf, "MiddlewareError|{e}")
286            }
287            ServerFnError::Deserialization(e) => {
288                write!(&mut buf, "Deserialization|{e}")
289            }
290            ServerFnError::Serialization(e) => {
291                write!(&mut buf, "Serialization|{e}")
292            }
293            ServerFnError::Args(e) => write!(&mut buf, "Args|{e}"),
294            ServerFnError::MissingArg(e) => {
295                write!(&mut buf, "MissingArg|{e}")
296            }
297        };
298
299        match result {
300            Ok(()) => Ok(Bytes::from(buf)),
301            Err(e) => Err(e),
302        }
303    }
304}
305
306impl<CustErr> Decodes<ServerFnError<CustErr>> for ServerFnErrorEncoding
307where
308    CustErr: FromStr,
309{
310    type Error = String;
311
312    fn decode(bytes: Bytes) -> Result<ServerFnError<CustErr>, Self::Error> {
313        let data = String::from_utf8(bytes.to_vec())
314            .map_err(|err| format!("UTF-8 conversion error: {err}"))?;
315
316        data.split_once('|')
317            .ok_or_else(|| {
318                format!("Invalid format: missing delimiter in {data:?}")
319            })
320            .and_then(|(ty, data)| match ty {
321                "WrappedServerFn" => CustErr::from_str(data)
322                    .map(ServerFnError::WrappedServerError)
323                    .map_err(|_| {
324                        format!("Failed to parse CustErr from {data:?}")
325                    }),
326                "Registration" => {
327                    Ok(ServerFnError::Registration(data.to_string()))
328                }
329                "Request" => Ok(ServerFnError::Request(data.to_string())),
330                "Response" => Ok(ServerFnError::Response(data.to_string())),
331                "ServerError" => {
332                    Ok(ServerFnError::ServerError(data.to_string()))
333                }
334                "MiddlewareError" => {
335                    Ok(ServerFnError::MiddlewareError(data.to_string()))
336                }
337                "Deserialization" => {
338                    Ok(ServerFnError::Deserialization(data.to_string()))
339                }
340                "Serialization" => {
341                    Ok(ServerFnError::Serialization(data.to_string()))
342                }
343                "Args" => Ok(ServerFnError::Args(data.to_string())),
344                "MissingArg" => Ok(ServerFnError::MissingArg(data.to_string())),
345                _ => Err(format!("Unknown error type: {ty}")),
346            })
347    }
348}
349
350impl<CustErr> FromServerFnError for ServerFnError<CustErr>
351where
352    CustErr: std::fmt::Debug + Display + FromStr + 'static,
353{
354    type Encoder = ServerFnErrorEncoding;
355
356    fn from_server_fn_error(value: ServerFnErrorErr) -> Self {
357        match value {
358            ServerFnErrorErr::Registration(value) => {
359                ServerFnError::Registration(value)
360            }
361            ServerFnErrorErr::Request(value) => ServerFnError::Request(value),
362            ServerFnErrorErr::ServerError(value) => {
363                ServerFnError::ServerError(value)
364            }
365            ServerFnErrorErr::MiddlewareError(value) => {
366                ServerFnError::MiddlewareError(value)
367            }
368            ServerFnErrorErr::Deserialization(value) => {
369                ServerFnError::Deserialization(value)
370            }
371            ServerFnErrorErr::Serialization(value) => {
372                ServerFnError::Serialization(value)
373            }
374            ServerFnErrorErr::Args(value) => ServerFnError::Args(value),
375            ServerFnErrorErr::MissingArg(value) => {
376                ServerFnError::MissingArg(value)
377            }
378            ServerFnErrorErr::Response(value) => ServerFnError::Response(value),
379            ServerFnErrorErr::UnsupportedRequestMethod(value) => {
380                ServerFnError::Request(value)
381            }
382        }
383    }
384}
385
386impl<E> std::error::Error for ServerFnError<E>
387where
388    E: std::error::Error + 'static,
389    ServerFnError<E>: std::fmt::Display,
390{
391    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
392        match self {
393            ServerFnError::WrappedServerError(e) => Some(e),
394            _ => None,
395        }
396    }
397}
398
399/// Type for errors that can occur when using server functions. If you need to return a custom error type from a server function, implement `FromServerFnError` for your custom error type.
400#[derive(
401    thiserror::Error, Debug, Clone, PartialEq, Eq, Serialize, Deserialize,
402)]
403#[cfg_attr(
404    feature = "rkyv",
405    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
406)]
407pub enum ServerFnErrorErr {
408    /// Error while trying to register the server function (only occurs in case of poisoned RwLock).
409    #[error("error while trying to register the server function: {0}")]
410    Registration(String),
411    /// Occurs on the client if trying to use an unsupported `HTTP` method when building a request.
412    #[error("error trying to build `HTTP` method request: {0}")]
413    UnsupportedRequestMethod(String),
414    /// Occurs on the client if there is a network error while trying to run function on server.
415    #[error("error reaching server to call server function: {0}")]
416    Request(String),
417    /// Occurs when there is an error while actually running the function on the server.
418    #[error("error running server function: {0}")]
419    ServerError(String),
420    /// Occurs when there is an error while actually running the middleware on the server.
421    #[error("error running middleware: {0}")]
422    MiddlewareError(String),
423    /// Occurs on the client if there is an error deserializing the server's response.
424    #[error("error deserializing server function results: {0}")]
425    Deserialization(String),
426    /// Occurs on the client if there is an error serializing the server function arguments.
427    #[error("error serializing server function arguments: {0}")]
428    Serialization(String),
429    /// Occurs on the server if there is an error deserializing one of the arguments that's been sent.
430    #[error("error deserializing server function arguments: {0}")]
431    Args(String),
432    /// Occurs on the server if there's a missing argument.
433    #[error("missing argument {0}")]
434    MissingArg(String),
435    /// Occurs on the server if there is an error creating an HTTP response.
436    #[error("error creating response {0}")]
437    Response(String),
438}
439
440/// Associates a particular server function error with the server function
441/// found at a particular path.
442///
443/// This can be used to pass an error from the server back to the client
444/// without JavaScript/WASM supported, by encoding it in the URL as a query string.
445/// This is useful for progressive enhancement.
446#[derive(Debug)]
447pub struct ServerFnUrlError<E> {
448    path: String,
449    error: E,
450}
451
452impl<E: FromServerFnError> ServerFnUrlError<E> {
453    /// Creates a new structure associating the server function at some path
454    /// with a particular error.
455    pub fn new(path: impl Display, error: E) -> Self {
456        Self {
457            path: path.to_string(),
458            error,
459        }
460    }
461
462    /// The error itself.
463    pub fn error(&self) -> &E {
464        &self.error
465    }
466
467    /// The path of the server function that generated this error.
468    pub fn path(&self) -> &str {
469        &self.path
470    }
471
472    /// Adds an encoded form of this server function error to the given base URL.
473    pub fn to_url(&self, base: &str) -> Result<Url, url::ParseError> {
474        let mut url = Url::parse(base)?;
475        url.query_pairs_mut()
476            .append_pair("__path", &self.path)
477            .append_pair("__err", &URL_SAFE.encode(self.error.ser()));
478        Ok(url)
479    }
480
481    /// Replaces any ServerFnUrlError info from the URL in the given string
482    /// with the serialized success value given.
483    pub fn strip_error_info(path: &mut String) {
484        if let Ok(mut url) = Url::parse(&*path) {
485            // NOTE: This is gross, but the Serializer you get from
486            // .query_pairs_mut() isn't an Iterator so you can't just .retain().
487            let pairs_previously = url
488                .query_pairs()
489                .map(|(k, v)| (k.to_string(), v.to_string()))
490                .collect::<Vec<_>>();
491            let mut pairs = url.query_pairs_mut();
492            pairs.clear();
493            for (key, value) in pairs_previously
494                .into_iter()
495                .filter(|(key, _)| key != "__path" && key != "__err")
496            {
497                pairs.append_pair(&key, &value);
498            }
499            drop(pairs);
500            *path = url.to_string();
501        }
502    }
503
504    /// Decodes an error from a URL.
505    pub fn decode_err(err: &str) -> E {
506        let decoded = match URL_SAFE.decode(err) {
507            Ok(decoded) => decoded,
508            Err(err) => {
509                return ServerFnErrorErr::Deserialization(err.to_string())
510                    .into_app_error();
511            }
512        };
513        E::de(decoded.into())
514    }
515}
516
517impl<E> From<ServerFnUrlError<E>> for ServerFnError<E> {
518    fn from(error: ServerFnUrlError<E>) -> Self {
519        error.error.into()
520    }
521}
522
523impl<E> From<ServerFnUrlError<ServerFnError<E>>> for ServerFnError<E> {
524    fn from(error: ServerFnUrlError<ServerFnError<E>>) -> Self {
525        error.error
526    }
527}
528
529#[derive(Debug, thiserror::Error)]
530#[doc(hidden)]
531/// Only used instantly only when a framework needs E: Error.
532pub struct ServerFnErrorWrapper<E: FromServerFnError>(pub E);
533
534impl<E: FromServerFnError> Display for ServerFnErrorWrapper<E> {
535    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
536        write!(
537            f,
538            "{}",
539            <E::Encoder as FormatType>::into_encoded_string(self.0.ser())
540        )
541    }
542}
543
544impl<E: FromServerFnError> FromStr for ServerFnErrorWrapper<E> {
545    type Err = base64::DecodeError;
546
547    fn from_str(s: &str) -> Result<Self, Self::Err> {
548        let bytes =
549            <E::Encoder as FormatType>::from_encoded_string(s).map_err(|e| {
550                E::from_server_fn_error(ServerFnErrorErr::Deserialization(
551                    e.to_string(),
552                ))
553            });
554        let bytes = match bytes {
555            Ok(bytes) => bytes,
556            Err(err) => return Ok(Self(err)),
557        };
558        let err = E::de(bytes);
559        Ok(Self(err))
560    }
561}
562
563/// A trait for types that can be returned from a server function.
564pub trait FromServerFnError: std::fmt::Debug + Sized + 'static {
565    /// The encoding strategy used to serialize and deserialize this error type. Must implement the [`Encodes`](server_fn::Encodes) trait for references to the error type.
566    type Encoder: Encodes<Self> + Decodes<Self>;
567
568    /// Converts a [`ServerFnErrorErr`] into the application-specific custom error type.
569    fn from_server_fn_error(value: ServerFnErrorErr) -> Self;
570
571    /// Serializes the custom error type to bytes, according to the encoding given by `Self::Encoding`.
572    fn ser(&self) -> Bytes {
573        Self::Encoder::encode(self).unwrap_or_else(|e| {
574            Self::Encoder::encode(&Self::from_server_fn_error(
575                ServerFnErrorErr::Serialization(e.to_string()),
576            ))
577            .expect(
578                "error serializing should success at least with the \
579                 Serialization error",
580            )
581        })
582    }
583
584    /// Deserializes the custom error type, according to the encoding given by `Self::Encoding`.
585    fn de(data: Bytes) -> Self {
586        Self::Encoder::decode(data).unwrap_or_else(|e| {
587            ServerFnErrorErr::Deserialization(e.to_string()).into_app_error()
588        })
589    }
590}
591
592/// A helper trait for converting a [`ServerFnErrorErr`] into an application-specific custom error type that implements [`FromServerFnError`].
593pub trait IntoAppError<E> {
594    /// Converts a [`ServerFnErrorErr`] into the application-specific custom error type.
595    fn into_app_error(self) -> E;
596}
597
598impl<E> IntoAppError<E> for ServerFnErrorErr
599where
600    E: FromServerFnError,
601{
602    fn into_app_error(self) -> E {
603        E::from_server_fn_error(self)
604    }
605}
606
607#[doc(hidden)]
608#[rustversion::attr(
609    since(1.78),
610    diagnostic::on_unimplemented(
611        message = "{Self} is not a `Result` or aliased `Result`. Server \
612                   functions must return a `Result` or aliased `Result`.",
613        label = "Must return a `Result` or aliased `Result`.",
614        note = "If you are trying to return an alias of `Result`, you must \
615                also implement `FromServerFnError` for the error type."
616    )
617)]
618/// A trait for extracting the error and ok types from a [`Result`]. This is used to allow alias types to be returned from server functions.
619pub trait ServerFnMustReturnResult {
620    /// The error type of the [`Result`].
621    type Err;
622    /// The ok type of the [`Result`].
623    type Ok;
624}
625
626#[doc(hidden)]
627impl<T, E> ServerFnMustReturnResult for Result<T, E> {
628    type Err = E;
629    type Ok = T;
630}
631
632#[test]
633fn assert_from_server_fn_error_impl() {
634    fn assert_impl<T: FromServerFnError>() {}
635
636    assert_impl::<ServerFnError>();
637}