shoutdotdev/src/app_error.rs

84 lines
2.9 KiB
Rust
Raw Normal View History

2025-02-16 13:06:38 -08:00
use std::fmt::{self, Display};
2024-11-01 00:07:33 -07:00
use axum::http::StatusCode;
2025-02-19 23:41:40 -08:00
use axum::response::{IntoResponse, Redirect, Response};
#[derive(Debug)]
pub struct AuthRedirectInfo {
base_path: String,
}
2024-11-01 00:07:33 -07:00
// Use anyhow, define error and enable '?'
// For a simplified example of using anyhow in axum check /examples/anyhow-error-response
#[derive(Debug)]
pub enum AppError {
2025-02-16 13:06:38 -08:00
InternalServerError(anyhow::Error),
ForbiddenError(String),
2025-02-16 13:06:38 -08:00
NotFoundError(String),
BadRequestError(String),
2025-02-19 23:41:40 -08:00
AuthRedirect(AuthRedirectInfo),
}
impl AppError {
pub fn auth_redirect_from_base_path(base_path: String) -> Self {
Self::AuthRedirect(AuthRedirectInfo { base_path })
}
2024-11-01 00:07:33 -07:00
}
// Tell axum how to convert `AppError` into a response.
impl IntoResponse for AppError {
fn into_response(self) -> Response {
match self {
2025-02-19 23:41:40 -08:00
Self::AuthRedirect(AuthRedirectInfo { base_path }) => {
tracing::debug!("Handling AuthRedirect");
Redirect::to(&format!("{}/auth/login", base_path)).into_response()
}
2024-11-01 00:07:33 -07:00
Self::InternalServerError(err) => {
2025-01-31 14:30:08 -08:00
tracing::error!("Application error: {:?}", err);
2024-11-01 00:07:33 -07:00
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong").into_response()
}
Self::ForbiddenError(client_message) => {
tracing::info!("Forbidden: {}", client_message);
(StatusCode::FORBIDDEN, client_message).into_response()
}
2025-02-16 13:06:38 -08:00
Self::NotFoundError(client_message) => {
tracing::info!("Not found: {}", client_message);
(StatusCode::NOT_FOUND, client_message).into_response()
}
Self::BadRequestError(client_message) => {
tracing::info!("Bad user input: {}", client_message);
(StatusCode::BAD_REQUEST, client_message).into_response()
}
2024-11-01 00:07:33 -07:00
}
}
}
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
// `Result<_, AppError>`. That way you don't need to do that manually.
impl<E> From<E> for AppError
where
E: Into<anyhow::Error>,
{
fn from(err: E) -> Self {
Self::InternalServerError(Into::<anyhow::Error>::into(err))
}
}
2025-02-16 13:06:38 -08:00
impl Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
2025-02-19 23:41:40 -08:00
AppError::AuthRedirect(info) => write!(f, "AuthRedirect: {:?}", info),
2025-02-16 13:06:38 -08:00
AppError::InternalServerError(inner) => inner.fmt(f),
AppError::ForbiddenError(client_message) => {
write!(f, "ForbiddenError: {}", client_message)
}
AppError::NotFoundError(client_message) => {
write!(f, "NotFoundError: {}", client_message)
}
AppError::BadRequestError(client_message) => {
write!(f, "BadRequestError: {}", client_message)
}
}
}
}