1use crate::response::Response;
2use thiserror::Error as ThisError;
3
4#[derive(Debug, ThisError)]
6pub enum Error {
7 #[error("not found")]
8 NotFound,
9
10 #[error("unauthorized")]
11 Unauthorized,
12
13 #[error("forbidden")]
14 Forbidden,
15
16 #[error("bad request: {0}")]
17 BadRequest(String),
18
19 #[error("payload too large")]
20 PayloadTooLarge,
21
22 #[error("method not allowed")]
23 MethodNotAllowed,
24
25 #[error("internal error: {0}")]
26 Internal(String),
27
28 #[error("json error: {0}")]
29 Json(#[from] serde_json::Error),
30
31 #[error("io error: {0}")]
32 Io(#[from] std::io::Error),
33
34 #[error("response")]
36 Response(Box<Response>),
37}
38
39pub type Result<T> = std::result::Result<T, Error>;
40
41impl Error {
42 pub fn bad_request(msg: impl Into<String>) -> Self {
44 Self::BadRequest(msg.into())
45 }
46
47 pub fn custom(status: u16, body: impl IntoResponse) -> Self {
49 Error::Response(Box::new(body.into_response().status(status)))
50 }
51
52 pub fn into_response(self) -> Response {
53 match self {
54 Error::NotFound => Response::text("Not Found").status(404),
55 Error::Unauthorized => Response::text("Unauthorized").status(401),
56 Error::Forbidden => Response::text("Forbidden").status(403),
57 Error::BadRequest(msg) => Response::text(msg).status(400),
58 Error::PayloadTooLarge => Response::text("Payload Too Large").status(413),
59 Error::MethodNotAllowed => Response::text("Method Not Allowed").status(405),
60 Error::Internal(msg) => Response::text(msg).status(500),
61 Error::Json(err) => Response::text(format!("JSON error: {err}")).status(400),
62 Error::Io(err) => Response::text(format!("IO error: {err}")).status(500),
63 Error::Response(res) => *res,
64 }
65 }
66}
67
68pub trait IntoResponse {
70 fn into_response(self) -> Response;
71}
72
73impl IntoResponse for Response {
74 fn into_response(self) -> Response {
75 self
76 }
77}
78
79impl IntoResponse for Error {
80 fn into_response(self) -> Response {
81 Error::into_response(self)
82 }
83}
84
85impl IntoResponse for String {
86 fn into_response(self) -> Response {
87 Response::text(self)
88 }
89}
90
91impl IntoResponse for &str {
92 fn into_response(self) -> Response {
93 Response::text(self)
94 }
95}