1use axum::http::StatusCode;
2use serde::Serialize;
3use serde_json::{Map, Value};
4
5#[derive(Debug, Clone, Serialize)]
7pub struct AwsError {
8 #[serde(skip)]
10 pub status: StatusCode,
11
12 pub code: String,
14
15 pub message: String,
17
18 pub error_type: ErrorType,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
32 pub extras: Option<Box<Map<String, Value>>>,
33}
34
35#[derive(Debug, Clone, Serialize)]
36pub enum ErrorType {
37 Sender,
38 Receiver,
39}
40
41impl AwsError {
42 pub fn not_found(code: impl Into<String>, message: impl Into<String>) -> Self {
43 Self {
44 status: StatusCode::NOT_FOUND,
45 code: code.into(),
46 message: message.into(),
47 error_type: ErrorType::Sender,
48 extras: None,
49 }
50 }
51
52 pub fn service_not_found(code: impl Into<String>, message: impl Into<String>) -> Self {
60 Self {
61 status: StatusCode::BAD_REQUEST,
62 code: code.into(),
63 message: message.into(),
64 error_type: ErrorType::Sender,
65 extras: None,
66 }
67 }
68
69 pub fn bad_request(code: impl Into<String>, message: impl Into<String>) -> Self {
70 Self {
71 status: StatusCode::BAD_REQUEST,
72 code: code.into(),
73 message: message.into(),
74 error_type: ErrorType::Sender,
75 extras: None,
76 }
77 }
78
79 pub fn range_not_satisfiable(code: impl Into<String>, message: impl Into<String>) -> Self {
82 Self {
83 status: StatusCode::RANGE_NOT_SATISFIABLE,
84 code: code.into(),
85 message: message.into(),
86 error_type: ErrorType::Sender,
87 extras: None,
88 }
89 }
90
91 pub fn precondition_failed(code: impl Into<String>, message: impl Into<String>) -> Self {
94 Self {
95 status: StatusCode::PRECONDITION_FAILED,
96 code: code.into(),
97 message: message.into(),
98 error_type: ErrorType::Sender,
99 extras: None,
100 }
101 }
102
103 pub fn conflict(code: impl Into<String>, message: impl Into<String>) -> Self {
104 Self {
105 status: StatusCode::CONFLICT,
106 code: code.into(),
107 message: message.into(),
108 error_type: ErrorType::Sender,
109 extras: None,
110 }
111 }
112
113 pub fn internal(message: impl Into<String>) -> Self {
114 Self {
115 status: StatusCode::INTERNAL_SERVER_ERROR,
116 code: "InternalServiceError".to_string(),
117 message: message.into(),
118 error_type: ErrorType::Receiver,
119 extras: None,
120 }
121 }
122
123 pub fn not_implemented(operation: &str) -> Self {
124 Self {
125 status: StatusCode::NOT_IMPLEMENTED,
126 code: "NotImplemented".to_string(),
127 message: format!("Operation '{operation}' is not yet implemented in AWSim"),
128 error_type: ErrorType::Receiver,
129 extras: None,
130 }
131 }
132
133 pub fn unknown_operation(operation: &str) -> Self {
134 Self {
135 status: StatusCode::BAD_REQUEST,
136 code: "UnknownOperationException".to_string(),
137 message: format!("Unknown operation: {operation}"),
138 error_type: ErrorType::Sender,
139 extras: None,
140 }
141 }
142
143 pub fn access_denied(message: impl Into<String>) -> Self {
144 Self {
145 status: StatusCode::FORBIDDEN,
146 code: "AccessDeniedException".to_string(),
147 message: message.into(),
148 error_type: ErrorType::Sender,
149 extras: None,
150 }
151 }
152
153 pub fn access_denied_for(action: &str, principal_arn: &str, resource: &str) -> Self {
154 Self {
155 status: StatusCode::FORBIDDEN,
156 code: "AccessDenied".to_string(),
157 message: format!(
158 "User: {principal_arn} is not authorized to perform: {action} on resource: {resource}"
159 ),
160 error_type: ErrorType::Sender,
161 extras: None,
162 }
163 }
164
165 pub fn validation(message: impl Into<String>) -> Self {
166 Self {
167 status: StatusCode::BAD_REQUEST,
168 code: "ValidationException".to_string(),
169 message: message.into(),
170 error_type: ErrorType::Sender,
171 extras: None,
172 }
173 }
174
175 pub fn with_extras(mut self, extras: Map<String, Value>) -> Self {
177 self.extras = Some(Box::new(extras));
178 self
179 }
180
181 pub fn with_extra(mut self, key: impl Into<String>, value: Value) -> Self {
183 self.extras
184 .get_or_insert_with(|| Box::new(Map::new()))
185 .insert(key.into(), value);
186 self
187 }
188}
189
190impl std::fmt::Display for AwsError {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 write!(f, "{}: {}", self.code, self.message)
193 }
194}
195
196impl std::error::Error for AwsError {}