spring_web/error.rs
1#![allow(missing_docs)]
2use axum::{
3 http::StatusCode,
4 response::{IntoResponse, Response},
5};
6use spring::error::AppError;
7use thiserror::Error;
8
9pub type Result<T> = std::result::Result<T, WebError>;
10
11/// <https://tools.ietf.org/html/rfc7231>
12#[derive(Error, Debug)]
13#[error("request error, status code is {status_code}: {msg}")]
14pub struct KnownWebError {
15 status_code: StatusCode,
16 msg: String,
17}
18
19macro_rules! impl_known_status_error {
20 (
21 $(
22 $(#[$docs:meta])*
23 $lower_case:ident, $upper_case:ident,
24 )+
25 ) => {
26 impl KnownWebError {
27 pub fn new<S:Into<String>>(status_code: StatusCode, msg: S) -> Self {
28 Self {
29 status_code,
30 msg: msg.into(),
31 }
32 }
33 $(
34 $(#[$docs])*
35 pub fn $lower_case<S:Into<String>>(msg: S) -> Self {
36 Self::new(StatusCode::$upper_case, msg)
37 }
38 )+
39 }
40 };
41}
42
43impl_known_status_error! (
44 /// 200 OK
45 /// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)]
46 ok, OK,
47 /// 201 Created
48 /// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)]
49 created, CREATED,
50 /// 202 Accepted
51 /// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)]
52 accepted, ACCEPTED,
53 /// 203 Non-Authoritative Information
54 /// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)]
55 non_authoritative_information, NON_AUTHORITATIVE_INFORMATION,
56 /// 204 No Content
57 /// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)]
58 no_content, NO_CONTENT,
59 /// 205 Reset Content
60 /// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)]
61 reset_content, RESET_CONTENT,
62 /// 206 Partial Content
63 /// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)]
64 partial_content, PARTIAL_CONTENT,
65 /// 207 Multi-Status
66 /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
67 multi_status, MULTI_STATUS,
68 /// 208 Already Reported
69 /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
70 already_reported, ALREADY_REPORTED,
71
72
73 /// 226 IM Used
74 /// [[RFC3229](https://tools.ietf.org/html/rfc3229)]
75 im_used, IM_USED,
76
77
78 /// 300 Multiple Choices
79 /// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)]
80 multiple_choices, MULTIPLE_CHOICES,
81 /// 301 Moved Permanently
82 /// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)]
83 moved_permanently, MOVED_PERMANENTLY,
84 /// 302 Found
85 /// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)]
86 found, FOUND,
87 /// 303 See Other
88 /// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)]
89 see_other, SEE_OTHER,
90 /// 304 Not Modified
91 /// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)]
92 not_modified, NOT_MODIFIED,
93 /// 305 Use Proxy
94 /// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)]
95 use_proxy, USE_PROXY,
96 /// 307 Temporary Redirect
97 /// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)]
98 temporary_redirect, TEMPORARY_REDIRECT,
99 /// 308 Permanent Redirect
100 /// [[RFC7238](https://tools.ietf.org/html/rfc7238)]
101 permanent_redirect, PERMANENT_REDIRECT,
102
103
104 /// 400 Bad Request
105 /// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)]
106 bad_request, BAD_REQUEST,
107 /// 401 Unauthorized
108 /// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)]
109 unauthorized, UNAUTHORIZED,
110 /// 402 Payment Required
111 /// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)]
112 payment_required, PAYMENT_REQUIRED,
113 /// 403 Forbidden
114 /// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)]
115 forbidden, FORBIDDEN,
116 /// 404 Not Found
117 /// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)]
118 not_found, NOT_FOUND,
119 /// 405 Method Not Allowed
120 /// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)]
121 method_not_allowed, METHOD_NOT_ALLOWED,
122 /// 406 Not Acceptable
123 /// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)]
124 not_acceptable, NOT_ACCEPTABLE,
125 /// 407 Proxy Authentication Required
126 /// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)]
127 proxy_authentication_required, PROXY_AUTHENTICATION_REQUIRED,
128 /// 408 Request Timeout
129 /// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)]
130 request_timeout, REQUEST_TIMEOUT,
131 /// 409 Conflict
132 /// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)]
133 conflict, CONFLICT,
134 /// 410 Gone
135 /// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)]
136 gone, GONE,
137 /// 411 Length Required
138 /// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)]
139 length_required, LENGTH_REQUIRED,
140 /// 412 Precondition Failed
141 /// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)]
142 precondition_failed, PRECONDITION_FAILED,
143 /// 413 Payload Too Large
144 /// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)]
145 payload_too_large, PAYLOAD_TOO_LARGE,
146 /// 414 URI Too Long
147 /// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)]
148 uri_too_long, URI_TOO_LONG,
149 /// 415 Unsupported Media Type
150 /// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)]
151 unsupported_media_type, UNSUPPORTED_MEDIA_TYPE,
152 /// 416 Range Not Satisfiable
153 /// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)]
154 range_not_satisfiable, RANGE_NOT_SATISFIABLE,
155 /// 417 Expectation Failed
156 /// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)]
157 expectation_failed, EXPECTATION_FAILED,
158 /// 418 I'm a teapot
159 /// [curiously not registered by IANA but [RFC2324](https://tools.ietf.org/html/rfc2324)]
160 im_a_teapot, IM_A_TEAPOT,
161
162
163 /// 421 Misdirected Request
164 /// [RFC7540, Section 9.1.2](https://tools.ietf.org/html/rfc7540#section-9.1.2)
165 misdirected_request, MISDIRECTED_REQUEST,
166 /// 422 Unprocessable Entity
167 /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
168 unprocessable_entity, UNPROCESSABLE_ENTITY,
169 /// 423 Locked
170 /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
171 locked, LOCKED,
172 /// 424 Failed Dependency
173 /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
174 failed_dependency, FAILED_DEPENDENCY,
175
176
177 /// 426 Upgrade Required
178 /// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)]
179 upgrade_required, UPGRADE_REQUIRED,
180
181
182 /// 428 Precondition Required
183 /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
184 precondition_required, PRECONDITION_REQUIRED,
185 /// 429 Too Many Requests
186 /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
187 too_many_requests, TOO_MANY_REQUESTS,
188
189
190 /// 431 Request Header Fields Too Large
191 /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
192 request_header_fields_too_large, REQUEST_HEADER_FIELDS_TOO_LARGE,
193
194
195 /// 451 Unavailable For Legal Reasons
196 /// [[RFC7725](https://tools.ietf.org/html/rfc7725)]
197 unavailable_for_legal_reasons, UNAVAILABLE_FOR_LEGAL_REASONS,
198
199
200 /// 500 Internal Server Error
201 /// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)]
202 internal_server_error, INTERNAL_SERVER_ERROR,
203 /// 501 Not Implemented
204 /// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)]
205 not_implemented, NOT_IMPLEMENTED,
206 /// 502 Bad Gateway
207 /// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)]
208 bad_gateway, BAD_GATEWAY,
209 /// 503 Service Unavailable
210 /// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)]
211 service_unavailable, SERVICE_UNAVAILABLE,
212 /// 504 Gateway Timeout
213 /// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)]
214 gateway_timeout, GATEWAY_TIMEOUT,
215 /// 505 HTTP Version Not Supported
216 /// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)]
217 http_version_not_supported, HTTP_VERSION_NOT_SUPPORTED,
218 /// 506 Variant Also Negotiates
219 /// [[RFC2295](https://tools.ietf.org/html/rfc2295)]
220 variant_also_negotiates, VARIANT_ALSO_NEGOTIATES,
221 /// 507 Insufficient Storage
222 /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
223 insufficient_storage, INSUFFICIENT_STORAGE,
224 /// 508 Loop Detected
225 /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
226 loop_detected, LOOP_DETECTED,
227
228
229 /// 510 Not Extended
230 /// [[RFC2774](https://tools.ietf.org/html/rfc2774)]
231 not_extended, NOT_EXTENDED,
232 /// 511 Network Authentication Required
233 /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
234 network_authentication_required, NETWORK_AUTHENTICATION_REQUIRED,
235
236);
237
238#[derive(Error, Debug)]
239pub enum WebError {
240 #[error(transparent)]
241 ResponseStatusError(#[from] KnownWebError),
242
243 #[error("get server config failed for typeof {0}, {1}")]
244 ConfigDeserializeErr(&'static str, Box<AppError>),
245
246 #[error(transparent)]
247 ServerError(#[from] anyhow::Error),
248}
249
250// Tell axum how to convert `AppError` into a response.
251impl IntoResponse for WebError {
252 fn into_response(self) -> Response {
253 match self {
254 Self::ResponseStatusError(e) => {
255 tracing::warn!("handler error:{:?}", e);
256 (e.status_code, e.msg)
257 }
258 _other => {
259 tracing::error!("internal server error:{:?}", _other);
260 (
261 StatusCode::INTERNAL_SERVER_ERROR,
262 format!("Something went wrong: {}", _other),
263 )
264 }
265 }
266 .into_response()
267 }
268}