Add a base struct for api error responses (#524)

Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
This commit is contained in:
Sampras Lopes
2023-02-10 19:42:08 +05:30
committed by GitHub
parent 1bdc8955c2
commit ff347193fe
8 changed files with 186 additions and 11 deletions

View File

@ -0,0 +1,28 @@
use super::types::ApiErrorResponse;
impl actix_web::ResponseError for ApiErrorResponse {
fn status_code(&self) -> reqwest::StatusCode {
use reqwest::StatusCode;
match self {
Self::Unauthorized(_) => StatusCode::UNAUTHORIZED,
Self::ForbiddenCommonResource(_) => StatusCode::FORBIDDEN,
Self::ForbiddenPrivateResource(_) => StatusCode::NOT_FOUND,
Self::Conflict(_) => StatusCode::CONFLICT,
Self::Gone(_) => StatusCode::GONE,
Self::Unprocessable(_) => StatusCode::UNPROCESSABLE_ENTITY,
Self::InternalServerError(_) => StatusCode::INTERNAL_SERVER_ERROR,
Self::NotImplemented(_) => StatusCode::NOT_IMPLEMENTED,
Self::ConnectorError(_, code) => *code,
}
}
fn error_response(&self) -> actix_web::HttpResponse {
use actix_web::http::header;
actix_web::HttpResponseBuilder::new(self.status_code())
.insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON))
.insert_header((header::VIA, "Juspay_Router"))
.body(self.to_string())
}
}

View File

@ -0,0 +1,3 @@
pub mod actix;
pub mod serde;
pub mod types;

View File

@ -0,0 +1,23 @@
use serde::{ser::SerializeMap, Serialize};
use super::types::ApiErrorResponse;
impl Serialize for ApiErrorResponse {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut map = serializer.serialize_map(Some(3))?;
map.serialize_entry("error_type", self.error_type())?;
map.serialize_entry(
"error_code",
&format!(
"{}_{}",
self.get_internal_error().sub_code,
self.get_internal_error().error_identifier
),
)?;
map.serialize_entry("error_message", self.get_internal_error().error_message)?;
map.end()
}
}

View File

@ -0,0 +1,68 @@
use reqwest::StatusCode;
pub enum ErrorType {
InvalidRequestError,
RouterError,
ConnectorError,
}
#[derive(Debug, serde::Serialize)]
pub struct ApiError {
pub sub_code: &'static str,
pub error_identifier: u8,
pub error_message: &'static str,
}
#[derive(Debug)]
pub enum ApiErrorResponse {
Unauthorized(ApiError),
ForbiddenCommonResource(ApiError),
ForbiddenPrivateResource(ApiError),
Conflict(ApiError),
Gone(ApiError),
Unprocessable(ApiError),
InternalServerError(ApiError),
NotImplemented(ApiError),
ConnectorError(ApiError, StatusCode),
}
impl ::core::fmt::Display for ApiErrorResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
r#"{{"error":{}}}"#,
serde_json::to_string(self.get_internal_error())
.unwrap_or_else(|_| "API error response".to_string())
)
}
}
impl ApiErrorResponse {
pub(crate) fn get_internal_error(&self) -> &ApiError {
match self {
Self::Unauthorized(i)
| Self::ForbiddenCommonResource(i)
| Self::ForbiddenPrivateResource(i)
| Self::Conflict(i)
| Self::Gone(i)
| Self::Unprocessable(i)
| Self::InternalServerError(i)
| Self::NotImplemented(i)
| Self::ConnectorError(i, _) => i,
}
}
pub(crate) fn error_type(&self) -> &str {
match self {
Self::Unauthorized(_)
| Self::ForbiddenCommonResource(_)
| Self::ForbiddenPrivateResource(_)
| Self::Conflict(_)
| Self::Gone(_)
| Self::Unprocessable(_)
| Self::NotImplemented(_) => "invalid_request",
Self::InternalServerError(_) => "api",
Self::ConnectorError(_, _) => "connector",
}
}
}

View File

@ -6,6 +6,7 @@ pub mod cards;
pub mod customers;
pub mod disputes;
pub mod enums;
pub mod errors;
pub mod files;
pub mod mandates;
pub mod payment_methods;