trz_gateway_common/
http_error.rs

1//! Adapt Rust errors to HTTP status codes.
2
3use std::convert::Infallible;
4
5use axum::http::StatusCode;
6use axum::response::IntoResponse;
7use axum::response::Response;
8
9/// A trait implemented by errors that translate to HTTP status codes.
10pub 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/// A wrapper to translate errors into http [Response]s.
21#[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}