diff --git a/crates/api_models/src/errors/types.rs b/crates/api_models/src/errors/types.rs index 365be676f167..5f303f93c56b 100644 --- a/crates/api_models/src/errors/types.rs +++ b/crates/api_models/src/errors/types.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use reqwest::StatusCode; +use serde::Serialize; #[derive(Debug, serde::Serialize)] pub enum ErrorType { @@ -78,7 +79,8 @@ pub struct Extra { pub reason: Option, } -#[derive(Debug, Clone)] +#[derive(Serialize, Debug, Clone)] +#[serde(tag = "type", content = "value")] pub enum ApiErrorResponse { Unauthorized(ApiError), ForbiddenCommonResource(ApiError), @@ -88,7 +90,7 @@ pub enum ApiErrorResponse { Unprocessable(ApiError), InternalServerError(ApiError), NotImplemented(ApiError), - ConnectorError(ApiError, StatusCode), + ConnectorError(ApiError, #[serde(skip_serializing)] StatusCode), NotFound(ApiError), MethodNotAllowed(ApiError), BadRequest(ApiError), diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs index 9bbe35ba2a9d..67154ae33aef 100644 --- a/crates/router/src/core/webhooks.rs +++ b/crates/router/src/core/webhooks.rs @@ -913,6 +913,7 @@ pub async fn webhooks_wrapper, url_path: String, response: Option, + error: Option, #[serde(flatten)] event_type: ApiEventsType, hs_latency: Option, @@ -52,6 +53,7 @@ impl ApiEvent { response: Option, hs_latency: Option, auth_type: AuthenticationType, + error: Option, event_type: ApiEventsType, http_req: &HttpRequest, ) -> Self { @@ -64,6 +66,7 @@ impl ApiEvent { request, response, auth_type, + error, ip_addr: http_req .connection_info() .realip_remote_addr() diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 0a8b84ffd11c..aae17195517d 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -769,7 +769,7 @@ where T: Debug + Serialize + ApiEventMetric, A: AppStateInfo + Clone, E: ErrorSwitch + error_stack::Context, - OErr: ResponseError + error_stack::Context, + OErr: ResponseError + error_stack::Context + Serialize, errors::ApiErrorResponse: ErrorSwitch, { let request_id = RequestId::extract(request) @@ -826,7 +826,9 @@ where .as_millis(); let mut serialized_response = None; + let mut error = None; let mut overhead_latency = None; + let status_code = match output.as_ref() { Ok(res) => { if let ApplicationResponse::Json(data) = res { @@ -854,7 +856,17 @@ where metrics::request::track_response_status_code(res) } - Err(err) => err.current_context().status_code().as_u16().into(), + Err(err) => { + error.replace( + serde_json::to_value(err.current_context()) + .into_report() + .attach_printable("Failed to serialize json response") + .change_context(errors::ApiErrorResponse::InternalServerError.switch()) + .ok() + .into(), + ); + err.current_context().status_code().as_u16().into() + } }; let api_event = ApiEvent::new( @@ -866,6 +878,7 @@ where serialized_response, overhead_latency, auth_type, + error, event_type.unwrap_or(ApiEventsType::Miscellaneous), request, );