Files
truelayer-interview/src/error.rs

60 lines
1.7 KiB
Rust

use axum::{Json, http::StatusCode, response::IntoResponse};
use serde::Serialize;
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("bad request: {0}")]
BadRequest(String),
#[error("pokemon not found")]
NotFound,
#[error("upstream service returned invalid data: {0}")]
InvalidUpstreamData(String),
#[error("upstream service failed: {0}")]
Upstream(String),
#[error("request timed out")]
Timeout,
#[error("internal server error")]
Internal,
}
impl AppError {
#[must_use]
pub const fn status_code(&self) -> StatusCode {
match self {
Self::BadRequest(_) => StatusCode::BAD_REQUEST,
Self::NotFound => StatusCode::NOT_FOUND,
Self::InvalidUpstreamData(_) | Self::Upstream(_) | Self::Timeout => {
StatusCode::BAD_GATEWAY
}
Self::Internal => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
impl IntoResponse for AppError {
fn into_response(self) -> axum::response::Response {
let status = self.status_code();
let body = ErrorBody {
error: self.public_message(),
};
(status, Json(body)).into_response()
}
}
impl AppError {
fn public_message(&self) -> String {
match self {
Self::BadRequest(message) => message.clone(),
Self::NotFound => "pokemon not found".to_owned(),
Self::InvalidUpstreamData(_) => "upstream service returned invalid data".to_owned(),
Self::Upstream(_) | Self::Timeout => "upstream service failed".to_owned(),
Self::Internal => "internal server error".to_owned(),
}
}
}
#[derive(Serialize)]
struct ErrorBody {
error: String,
}