api_bones_test/builders/
problem.rs1use api_bones::error::{ApiError, ErrorCode, ValidationError};
2
3pub struct FakeProblem {
18 code: ErrorCode,
19 detail: Option<String>,
20 title: Option<String>,
21 status: Option<u16>,
22 request_id: Option<String>,
23 fields: Vec<(String, String)>,
24}
25
26impl FakeProblem {
27 #[must_use]
28 pub fn new(code: ErrorCode) -> Self {
29 Self {
30 code,
31 detail: None,
32 title: None,
33 status: None,
34 request_id: None,
35 fields: Vec::new(),
36 }
37 }
38
39 #[must_use]
40 pub fn detail(mut self, detail: impl Into<String>) -> Self {
41 self.detail = Some(detail.into());
42 self
43 }
44
45 #[must_use]
46 pub fn title(mut self, title: impl Into<String>) -> Self {
47 self.title = Some(title.into());
48 self
49 }
50
51 #[must_use]
52 pub fn field(mut self, name: impl Into<String>, message: impl Into<String>) -> Self {
53 self.fields.push((name.into(), message.into()));
54 self
55 }
56
57 #[must_use]
58 pub fn status(mut self, status: u16) -> Self {
59 self.status = Some(status);
60 self
61 }
62
63 #[must_use]
64 pub fn request_id(mut self, id: impl Into<String>) -> Self {
65 self.request_id = Some(id.into());
66 self
67 }
68
69 #[must_use]
70 pub fn build(self) -> ApiError {
71 let detail = self.detail.unwrap_or_else(|| self.code.title().to_string());
72 let mut err = ApiError::new(self.code, detail);
73 if let Some(title) = self.title {
74 err.title = title;
75 }
76 if let Some(status) = self.status {
77 err.status = status;
78 }
79 if let Some(id_str) = self.request_id {
80 if let Ok(uuid) = id_str.parse::<uuid::Uuid>() {
81 err = err.with_request_id(uuid);
82 }
83 }
84 if !self.fields.is_empty() {
85 let errors: Vec<ValidationError> = self
86 .fields
87 .into_iter()
88 .map(|(field, message)| ValidationError {
89 field,
90 message,
91 rule: None,
92 })
93 .collect();
94 err = err.with_errors(errors);
95 }
96 err
97 }
98}