use serde::Deserialize;
use crate::error::{ErrorCode, GraphQLError};
#[derive(Debug, Clone, Deserialize)]
#[serde(default)]
pub struct ErrorSanitizationConfig {
pub enabled: bool,
pub hide_implementation_details: bool,
pub sanitize_database_errors: bool,
pub custom_error_message: Option<String>,
}
impl Default for ErrorSanitizationConfig {
fn default() -> Self {
Self {
enabled: false,
hide_implementation_details: true,
sanitize_database_errors: true,
custom_error_message: None,
}
}
}
pub struct ErrorSanitizer {
config: ErrorSanitizationConfig,
}
impl ErrorSanitizer {
#[must_use]
pub const fn new(config: ErrorSanitizationConfig) -> Self {
Self { config }
}
#[must_use]
pub fn disabled() -> Self {
Self::new(ErrorSanitizationConfig::default())
}
#[must_use]
pub fn sanitize(&self, mut error: GraphQLError) -> GraphQLError {
if !self.config.enabled {
return error;
}
let is_internal =
matches!(error.code, ErrorCode::InternalServerError | ErrorCode::DatabaseError);
if is_internal && self.config.sanitize_database_errors {
error.message = self
.config
.custom_error_message
.clone()
.unwrap_or_else(|| "An internal error occurred".to_string());
}
if self.config.hide_implementation_details {
if let Some(ext) = error.extensions.as_mut() {
ext.detail = None;
}
}
error
}
#[must_use]
pub fn sanitize_all(&self, errors: Vec<GraphQLError>) -> Vec<GraphQLError> {
errors.into_iter().map(|e| self.sanitize(e)).collect()
}
#[must_use]
pub const fn is_enabled(&self) -> bool {
self.config.enabled
}
#[must_use]
pub const fn should_sanitize_internal(&self) -> bool {
self.config.enabled && self.config.sanitize_database_errors
}
#[must_use]
pub fn internal_error_message(&self) -> String {
self.config
.custom_error_message
.clone()
.unwrap_or_else(|| "An internal error occurred".to_string())
}
}