mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
feat(api_models): add error structs (#532)
Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
This commit is contained in:
@ -14,6 +14,9 @@ impl actix_web::ResponseError for ApiErrorResponse {
|
||||
Self::InternalServerError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Self::NotImplemented(_) => StatusCode::NOT_IMPLEMENTED,
|
||||
Self::ConnectorError(_, code) => *code,
|
||||
Self::MethodNotAllowed(_) => StatusCode::METHOD_NOT_ALLOWED,
|
||||
Self::NotFound(_) => StatusCode::NOT_FOUND,
|
||||
Self::BadRequest(_) => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
pub mod actix;
|
||||
pub mod serde;
|
||||
pub mod types;
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@ -1,19 +1,74 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use reqwest::StatusCode;
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub enum ErrorType {
|
||||
InvalidRequestError,
|
||||
RouterError,
|
||||
ConnectorError,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
#[derive(Debug, serde::Serialize, Clone)]
|
||||
pub struct ApiError {
|
||||
pub sub_code: &'static str,
|
||||
pub error_identifier: u8,
|
||||
pub error_message: &'static str,
|
||||
pub error_identifier: u16,
|
||||
pub error_message: String,
|
||||
pub extra: Option<Extra>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
impl ApiError {
|
||||
pub fn new(
|
||||
sub_code: &'static str,
|
||||
error_identifier: u16,
|
||||
error_message: impl ToString,
|
||||
extra: Option<Extra>,
|
||||
) -> Self {
|
||||
Self {
|
||||
sub_code,
|
||||
error_identifier,
|
||||
error_message: error_message.to_string(),
|
||||
extra,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
struct ErrorResponse<'a> {
|
||||
#[serde(rename = "type")]
|
||||
error_type: &'static str,
|
||||
message: Cow<'a, str>,
|
||||
code: String,
|
||||
#[serde(flatten)]
|
||||
extra: &'a Option<Extra>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ApiErrorResponse> for ErrorResponse<'a> {
|
||||
fn from(value: &'a ApiErrorResponse) -> Self {
|
||||
let error_info = value.get_internal_error();
|
||||
let error_type = value.error_type();
|
||||
Self {
|
||||
code: format!("{}_{}", error_info.sub_code, error_info.error_identifier),
|
||||
message: Cow::Borrowed(value.get_internal_error().error_message.as_str()),
|
||||
error_type,
|
||||
extra: &error_info.extra,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, Default, Clone)]
|
||||
pub struct Extra {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub payment_id: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<serde_json::Value>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub connector: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ApiErrorResponse {
|
||||
Unauthorized(ApiError),
|
||||
ForbiddenCommonResource(ApiError),
|
||||
@ -24,14 +79,18 @@ pub enum ApiErrorResponse {
|
||||
InternalServerError(ApiError),
|
||||
NotImplemented(ApiError),
|
||||
ConnectorError(ApiError, StatusCode),
|
||||
NotFound(ApiError),
|
||||
MethodNotAllowed(ApiError),
|
||||
BadRequest(ApiError),
|
||||
}
|
||||
|
||||
impl ::core::fmt::Display for ApiErrorResponse {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let error_response: ErrorResponse<'_> = self.into();
|
||||
write!(
|
||||
f,
|
||||
r#"{{"error":{}}}"#,
|
||||
serde_json::to_string(self.get_internal_error())
|
||||
serde_json::to_string(&error_response)
|
||||
.unwrap_or_else(|_| "API error response".to_string())
|
||||
)
|
||||
}
|
||||
@ -48,11 +107,14 @@ impl ApiErrorResponse {
|
||||
| Self::Unprocessable(i)
|
||||
| Self::InternalServerError(i)
|
||||
| Self::NotImplemented(i)
|
||||
| Self::NotFound(i)
|
||||
| Self::MethodNotAllowed(i)
|
||||
| Self::BadRequest(i)
|
||||
| Self::ConnectorError(i, _) => i,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn error_type(&self) -> &str {
|
||||
pub(crate) fn error_type(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Unauthorized(_)
|
||||
| Self::ForbiddenCommonResource(_)
|
||||
@ -60,9 +122,14 @@ impl ApiErrorResponse {
|
||||
| Self::Conflict(_)
|
||||
| Self::Gone(_)
|
||||
| Self::Unprocessable(_)
|
||||
| Self::NotImplemented(_) => "invalid_request",
|
||||
| Self::NotImplemented(_)
|
||||
| Self::MethodNotAllowed(_)
|
||||
| Self::NotFound(_)
|
||||
| Self::BadRequest(_) => "invalid_request",
|
||||
Self::InternalServerError(_) => "api",
|
||||
Self::ConnectorError(_, _) => "connector",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ApiErrorResponse {}
|
||||
|
||||
Reference in New Issue
Block a user