JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

Error handling refactor

This refactor aims to improve error handling throughout the project by refining the overarching error types and increasing usage of proper error handling. Replaced existing networked operation error with `NetworkOperationError`. `NetworkOperationError` does not forward any internal error details, which allows `OperationError` to grow into a better error type. `OperationError` now has support for storing real typed errors inside of it for better debugging. `IntoInternalError` is a trait which allows for easy conversion of error types into `OperationError::internal`.

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨e02c03d

⁨giterated-models/src/error.rs⁩ - ⁨2908⁩ bytes
Raw
1 use std::fmt::Display;
2
3 use serde::{Deserialize, Serialize};
4
5 #[derive(Debug, thiserror::Error, Deserialize, Serialize)]
6 pub enum InstanceError {
7 #[error("registration failed")]
8 RegistrationFailure,
9 #[error("authentication failed")]
10 AuthenticationFailed,
11 }
12
13 #[derive(Debug, thiserror::Error, Serialize, Deserialize)]
14 pub enum RepositoryError {}
15
16 #[derive(Debug, thiserror::Error, Deserialize, Serialize)]
17 pub enum UserError {}
18
19 #[derive(Debug, thiserror::Error, Serialize, Deserialize)]
20 pub enum GetValueError {
21 #[error("invalid object")]
22 InvalidObject,
23 }
24
25 #[derive(Debug, thiserror::Error)]
26 #[error("unauthorized")]
27 pub struct UnauthorizedError;
28
29 #[derive(Debug, thiserror::Error)]
30 pub enum OperationError<B> {
31 #[error("the operation was handled but an error occurred")]
32 Operation(#[from] B),
33 #[error("an internal error occurred: {0:?}")]
34 Internal(anyhow::Error),
35 #[error("the operation was unhandled or unrecognized")]
36 Unhandled,
37 }
38
39 pub trait IntoInternalError<T>: Sized {
40 fn as_internal_error<B>(self) -> Result<T, OperationError<B>>;
41
42 fn as_internal_error_with_context<B, C>(self, context: C) -> Result<T, OperationError<B>>
43 where
44 C: Display + Send + Sync + 'static,
45 {
46 let internal_error = self.as_internal_error::<B>();
47
48 match internal_error {
49 Ok(success) => Ok(success),
50 Err(OperationError::Internal(internal)) => {
51 Err(OperationError::Internal(internal.context(context)))
52 }
53 _ => unreachable!(),
54 }
55 }
56 }
57
58 impl<E: Into<anyhow::Error>, T> IntoInternalError<T> for Result<T, E> {
59 fn as_internal_error<B>(self) -> Result<T, OperationError<B>> {
60 match self {
61 Ok(success) => Ok(success),
62 Err(err) => Err(OperationError::Internal(err.into())),
63 }
64 }
65 }
66
67 impl<B> OperationError<B> {
68 pub fn into_network(self) -> NetworkOperationError<B> {
69 match self {
70 OperationError::Operation(operation_error) => {
71 NetworkOperationError::Operation(operation_error)
72 }
73 OperationError::Internal(_) => NetworkOperationError::Internal,
74 OperationError::Unhandled => NetworkOperationError::Unhandled,
75 }
76 }
77 }
78
79 #[derive(Debug, thiserror::Error)]
80 #[error("an extractor failed with an error {0}")]
81 pub struct ExtractorError<E: Into<anyhow::Error>>(#[from] pub E);
82
83 impl<T, E: Into<anyhow::Error>> IntoInternalError<T> for ExtractorError<E> {
84 fn as_internal_error<B>(self) -> Result<T, OperationError<B>> {
85 todo!()
86 }
87 }
88
89 #[derive(Serialize, Deserialize, Debug, thiserror::Error)]
90 pub enum NetworkOperationError<B> {
91 #[error("the operation was handled but an error occurred")]
92 Operation(#[from] B),
93 #[error("internal error")]
94 Internal,
95 #[error("the operation was unhandled or unrecognized")]
96 Unhandled,
97 }
98