Skip to main content

apigate_core/error/
framework.rs

1use std::borrow::Cow;
2
3use axum::response::{IntoResponse, Response};
4use http::StatusCode;
5use thiserror::Error;
6
7use super::{ApigateCoreError, ApigatePipelineError};
8
9#[derive(Debug, Error)]
10pub enum ApigateFrameworkError {
11    #[error(transparent)]
12    Core(#[from] ApigateCoreError),
13    #[error(transparent)]
14    Pipeline(#[from] ApigatePipelineError),
15    #[error("{message}")]
16    Http {
17        status: StatusCode,
18        message: Cow<'static, str>,
19    },
20}
21
22impl ApigateFrameworkError {
23    pub fn user_message(&self) -> &str {
24        match self {
25            Self::Core(err) => err.user_message(),
26            Self::Pipeline(err) => err.user_message(),
27            Self::Http { message, .. } => message.as_ref(),
28        }
29    }
30
31    pub fn debug_details(&self) -> Option<&str> {
32        match self {
33            Self::Core(err) => err.debug_details(),
34            Self::Pipeline(err) => err.debug_details(),
35            Self::Http { .. } => None,
36        }
37    }
38
39    pub fn status_code(&self) -> StatusCode {
40        match self {
41            Self::Core(err) => err.status_code(),
42            Self::Pipeline(err) => err.status_code(),
43            Self::Http { status, .. } => *status,
44        }
45    }
46
47    pub fn code(&self) -> &'static str {
48        match self {
49            Self::Core(err) => err.code(),
50            Self::Pipeline(err) => err.code(),
51            Self::Http { status, .. } => match *status {
52                StatusCode::BAD_REQUEST => "bad_request",
53                StatusCode::UNAUTHORIZED => "unauthorized",
54                StatusCode::FORBIDDEN => "forbidden",
55                StatusCode::PAYLOAD_TOO_LARGE => "payload_too_large",
56                StatusCode::UNSUPPORTED_MEDIA_TYPE => "unsupported_media_type",
57                StatusCode::BAD_GATEWAY => "bad_gateway",
58                StatusCode::GATEWAY_TIMEOUT => "gateway_timeout",
59                StatusCode::INTERNAL_SERVER_ERROR => "internal",
60                _ if status.is_client_error() => "client_error",
61                _ if status.is_server_error() => "server_error",
62                _ => "http_error",
63            },
64        }
65    }
66}
67
68pub type ErrorRenderer = dyn Fn(ApigateFrameworkError) -> Response + Send + Sync + 'static;
69
70pub fn default_error_renderer(error: ApigateFrameworkError) -> Response {
71    (
72        error.status_code(),
73        [("content-type", "text/plain; charset=utf-8")],
74        error.user_message().to_owned(),
75    )
76        .into_response()
77}