actix_web_validator/
error.rs1use actix_web::http::StatusCode;
3use actix_web::{HttpResponse, ResponseError};
4use thiserror::Error;
5use validator::{ValidationError, ValidationErrors, ValidationErrorsKind};
6
7#[derive(Error, Debug)]
8pub enum Error {
9 #[error("Validation error: {0}")]
10 Validate(#[from] validator::ValidationErrors),
11 #[error(transparent)]
12 Deserialize(#[from] DeserializeErrors),
13 #[error("Payload error: {0}")]
14 JsonPayloadError(#[from] actix_web::error::JsonPayloadError),
15 #[error("Url encoded error: {0}")]
16 UrlEncodedError(#[from] actix_web::error::UrlencodedError),
17 #[error("Query error: {0}")]
18 QsError(#[from] serde_qs::Error),
19}
20
21#[derive(Error, Debug)]
22pub enum DeserializeErrors {
23 #[error("Query deserialize error: {0}")]
24 DeserializeQuery(serde_urlencoded::de::Error),
25 #[error("Json deserialize error: {0}")]
26 DeserializeJson(serde_json::error::Error),
27 #[error("Path deserialize error: {0}")]
28 DeserializePath(serde::de::value::Error),
29}
30
31impl From<serde_json::error::Error> for Error {
32 fn from(error: serde_json::error::Error) -> Self {
33 Error::Deserialize(DeserializeErrors::DeserializeJson(error))
34 }
35}
36
37impl From<serde_urlencoded::de::Error> for Error {
38 fn from(error: serde_urlencoded::de::Error) -> Self {
39 Error::Deserialize(DeserializeErrors::DeserializeQuery(error))
40 }
41}
42
43impl ResponseError for Error {
44 fn error_response(&self) -> HttpResponse {
45 HttpResponse::build(StatusCode::BAD_REQUEST).body(match self {
46 Self::Validate(e) => {
47 format!(
48 "Validation errors in fields:\n{}",
49 flatten_errors(e)
50 .iter()
51 .map(|(_, field, err)| { format!("\t{field}: {err}") })
52 .collect::<Vec<_>>()
53 .join("\n")
54 )
55 }
56 _ => format!("{}", *self),
57 })
58 }
59}
60
61#[inline]
65pub fn flatten_errors(errors: &ValidationErrors) -> Vec<(u16, String, &ValidationError)> {
66 _flatten_errors(errors, None, None)
67}
68
69#[inline]
70fn _flatten_errors(
71 errors: &ValidationErrors,
72 path: Option<String>,
73 indent: Option<u16>,
74) -> Vec<(u16, String, &ValidationError)> {
75 errors
76 .errors()
77 .iter()
78 .flat_map(|(field, err)| {
79 let indent = indent.unwrap_or(0);
80 let actual_path = path
81 .as_ref()
82 .map(|path| [path.as_str(), field].join("."))
83 .unwrap_or_else(|| field.to_string());
84 match err {
85 ValidationErrorsKind::Field(field_errors) => field_errors
86 .iter()
87 .map(|error| (indent, actual_path.clone(), error))
88 .collect::<Vec<_>>(),
89 ValidationErrorsKind::List(list_error) => list_error
90 .iter()
91 .flat_map(|(index, errors)| {
92 let actual_path = format!("{}[{}]", actual_path.as_str(), index);
93 _flatten_errors(errors, Some(actual_path), Some(indent + 1))
94 })
95 .collect::<Vec<_>>(),
96 ValidationErrorsKind::Struct(struct_errors) => {
97 _flatten_errors(struct_errors, Some(actual_path), Some(indent + 1))
98 }
99 }
100 })
101 .collect::<Vec<_>>()
102}