Skip to content

Commit

Permalink
Error handling with thiserror (#494)
Browse files Browse the repository at this point in the history
* feat(db): add indexes for foreign key reference columns

* fix(db): index naming and missing semicolons

* dep(backend): update axum

* fix(backend): remove testing jwt handlers

* feat(backend): Add custom jwt validator and header

* feat(backend): basic error handling enum

* fix(backend): ran cargo fmt

* fix(backend): remove unused imports

* Change to using `thiserror`

* remove 'Error' from logic error names
  • Loading branch information
KavikaPalletenne authored Jun 28, 2024
1 parent 84f6324 commit 1405e97
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
1 change: 1 addition & 0 deletions backend/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres", "time"

# Important secondary crates
anyhow = "1.0"
thiserror = "1.0"
serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.11", features = ["json"] }
serde_json = "1.0"
Expand Down
3 changes: 2 additions & 1 deletion backend/server/src/models/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ where

let claims =
decode_auth_token(token, decoding_key, jwt_validator).ok_or(ChaosError::NotLoggedIn)?;

let pool = &app_state.db;
let possible_user = is_super_user(claims.sub, pool).await;

Expand All @@ -102,6 +103,6 @@ where
}
}

Err(ChaosError::NotLoggedIn)
Err(ChaosError::Unauthorized)
}
}
35 changes: 23 additions & 12 deletions backend/server/src/models/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,42 @@ use axum::response::{IntoResponse, Redirect, Response};

/// Custom error enum for Chaos.
///
/// Handles all anyhow errors (when `?` is used) alongside
/// Handles all errors thrown by libraries (when `?` is used) alongside
/// specific errors for business logic.
#[derive(thiserror::Error, Debug)]
pub enum ChaosError {
#[error("Not logged in")]
NotLoggedIn,

#[error("Not authorized")]
Unauthorized,

#[error("Forbidden operation")]
ForbiddenOperation,
ServerError(anyhow::Error),

#[error("SQLx error")]
DatabaseError(#[from] sqlx::Error),

#[error("Reqwest error")]
ReqwestError(#[from] reqwest::Error),

#[error("OAuth2 error")]
OAuthError(#[from] oauth2::RequestTokenError<oauth2::reqwest::Error<reqwest::Error>, oauth2::StandardErrorResponse<oauth2::basic::BasicErrorResponseType>>)
}

/// Implementation for converting errors into responses. Manages error code and message returned.
impl IntoResponse for ChaosError {
fn into_response(self) -> Response {
match self {
ChaosError::NotLoggedIn => Redirect::temporary("/auth/google").into_response(),
ChaosError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized").into_response(),
ChaosError::ForbiddenOperation => (StatusCode::FORBIDDEN, "Forbidden operation").into_response(),
ChaosError::ServerError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response()
ChaosError::DatabaseError(db_error) => match db_error {
// We only care about the RowNotFound error, as others are miscellaneous DB errors.
sqlx::Error::RowNotFound => (StatusCode::NOT_FOUND, "Not found").into_response(),
_ => (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error").into_response(),
},
_ => (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error").into_response()
}
}
}

impl<E> From<E> for ChaosError
where
E: Into<anyhow::Error>,
{
fn from(err: E) -> Self {
ChaosError::ServerError(err.into())
}
}

0 comments on commit 1405e97

Please sign in to comment.