use std::{error::Error, fmt::Display};
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde_json::{json, Value};
use tonic::Status;
#[derive(Debug)]
pub enum ServiceErrors {
NotFound(Status),
ServiceUnavailable(Status),
ServiceInternal(Status),
}
impl From<tonic::Status> for ServiceErrors {
fn from(status: tonic::Status) -> Self {
match status.code() {
tonic::Code::NotFound => ServiceErrors::NotFound(status),
tonic::Code::Unavailable => ServiceErrors::ServiceUnavailable(status),
_ => ServiceErrors::ServiceInternal(status),
}
}
}
impl From<tonic::transport::Error> for ServiceErrors {
fn from(error: tonic::transport::Error) -> Self {
ServiceErrors::ServiceUnavailable(Status::new(tonic::Code::Unavailable, error.to_string()))
}
}
impl Error for ServiceErrors {}
impl Display for ServiceErrors {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ServiceErrors::NotFound(e) => {
write!(f, "{}", e.message())
}
ServiceErrors::ServiceUnavailable(e) => {
write!(f, "{}", e.message())
}
ServiceErrors::ServiceInternal(e) => {
write!(f, "{}", e.message())
}
}
}
}
impl IntoResponse for ServiceErrors {
fn into_response(self) -> Response {
match self {
ServiceErrors::NotFound(e) => {
(StatusCode::NOT_FOUND, error_json(e.message().to_string()))
}
ServiceErrors::ServiceUnavailable(e) => (
StatusCode::GATEWAY_TIMEOUT,
error_json(e.message().to_string()),
),
ServiceErrors::ServiceInternal(e) => {
(StatusCode::BAD_GATEWAY, error_json(e.message().to_string()))
}
}
.into_response()
}
}
fn error_json(error: String) -> Json<Value> {
Json(json!({ "error": error }))
}