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}