feat(api_models): add error structs (#532)

Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
This commit is contained in:
Nishant Joshi
2023-02-16 14:49:14 +05:30
committed by GitHub
parent 326d6bebe1
commit d107b44fd3
11 changed files with 288 additions and 55 deletions

View File

@ -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,
}
}

View File

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

View File

@ -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()
}
}

View File

@ -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 {}