trz_gateway_common/
http_error.rs1use std::convert::Infallible;
4
5use axum::http::StatusCode;
6use axum::response::IntoResponse;
7use axum::response::Response;
8
9pub trait IsHttpError: std::error::Error + Sized {
11 fn status_code(&self) -> StatusCode;
12}
13
14impl<T: IsHttpError> IsHttpError for Box<T> {
15 fn status_code(&self) -> StatusCode {
16 self.as_ref().status_code()
17 }
18}
19
20#[derive(thiserror::Error, Debug, Clone)]
22#[error(transparent)]
23pub struct HttpError<E: IsHttpError>(#[from] E);
24
25impl<E: IsHttpError> IntoResponse for HttpError<E> {
26 fn into_response(self) -> Response {
27 (self.0.status_code(), self.to_string()).into_response()
28 }
29}
30
31impl IsHttpError for Infallible {
32 fn status_code(&self) -> StatusCode {
33 unreachable!()
34 }
35}
36
37impl IsHttpError for tonic::Status {
38 fn status_code(&self) -> StatusCode {
39 match self.code() {
40 tonic::Code::Ok => StatusCode::OK,
41 tonic::Code::Cancelled => StatusCode::from_u16(499).expect("Client Closed Request"),
42 tonic::Code::Unknown => StatusCode::INTERNAL_SERVER_ERROR,
43 tonic::Code::InvalidArgument => StatusCode::BAD_REQUEST,
44 tonic::Code::DeadlineExceeded => StatusCode::GATEWAY_TIMEOUT,
45 tonic::Code::NotFound => StatusCode::NOT_FOUND,
46 tonic::Code::AlreadyExists => StatusCode::CONFLICT,
47 tonic::Code::PermissionDenied => StatusCode::FORBIDDEN,
48 tonic::Code::ResourceExhausted => StatusCode::TOO_MANY_REQUESTS,
49 tonic::Code::FailedPrecondition => StatusCode::BAD_REQUEST,
50 tonic::Code::Aborted => StatusCode::CONFLICT,
51 tonic::Code::OutOfRange => StatusCode::BAD_REQUEST,
52 tonic::Code::Unimplemented => StatusCode::NOT_IMPLEMENTED,
53 tonic::Code::Internal => StatusCode::INTERNAL_SERVER_ERROR,
54 tonic::Code::Unavailable => StatusCode::SERVICE_UNAVAILABLE,
55 tonic::Code::DataLoss => StatusCode::INTERNAL_SERVER_ERROR,
56 tonic::Code::Unauthenticated => StatusCode::UNAUTHORIZED,
57 }
58 }
59}