1use std::fmt;
6
7pub type Result<T> = std::result::Result<T, Error>;
9
10#[derive(Debug)]
12pub enum Error {
13 BadRequest(String),
14 Unauthorized(String),
15 Forbidden(String),
16 NotFound(String),
17 MethodNotAllowed(String),
18 Conflict(String),
19 Internal(String),
20}
21
22impl Error {
23 pub fn status(&self) -> u16 {
25 match self {
26 Error::BadRequest(_) => 400,
27 Error::Unauthorized(_) => 401,
28 Error::Forbidden(_) => 403,
29 Error::NotFound(_) => 404,
30 Error::MethodNotAllowed(_) => 405,
31 Error::Conflict(_) => 409,
32 Error::Internal(_) => 500,
33 }
34 }
35
36 pub fn client_message(&self) -> &str {
40 match self {
41 Error::BadRequest(m)
42 | Error::Unauthorized(m)
43 | Error::Forbidden(m)
44 | Error::NotFound(m)
45 | Error::MethodNotAllowed(m)
46 | Error::Conflict(m) => m,
47 Error::Internal(_) => "Internal Server Error",
48 }
49 }
50}
51
52impl fmt::Display for Error {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 let label = match self {
55 Error::BadRequest(m) => format!("400 Bad Request: {m}"),
56 Error::Unauthorized(m) => format!("401 Unauthorized: {m}"),
57 Error::Forbidden(m) => format!("403 Forbidden: {m}"),
58 Error::NotFound(m) => format!("404 Not Found: {m}"),
59 Error::MethodNotAllowed(m) => format!("405 Method Not Allowed: {m}"),
60 Error::Conflict(m) => format!("409 Conflict: {m}"),
61 Error::Internal(m) => format!("500 Internal: {m}"),
62 };
63 f.write_str(&label)
64 }
65}
66
67impl std::error::Error for Error {}
68
69impl From<sqlx::Error> for Error {
70 fn from(e: sqlx::Error) -> Self {
71 match e {
72 sqlx::Error::RowNotFound => Error::NotFound("row not found".into()),
73 sqlx::Error::Database(db_err) if db_err.constraint().is_some() => {
78 let constraint = db_err.constraint().unwrap_or("?").to_string();
79 Error::Conflict(format!("constraint violation ({constraint}): {db_err}"))
80 }
81 other => Error::Internal(format!("db error: {other}")),
82 }
83 }
84}
85
86impl From<std::io::Error> for Error {
87 fn from(e: std::io::Error) -> Self {
88 Error::Internal(format!("io error: {e}"))
89 }
90}
91
92impl From<serde_json::Error> for Error {
93 fn from(e: serde_json::Error) -> Self {
94 Error::BadRequest(format!("json error: {e}"))
95 }
96}
97
98impl From<minijinja::Error> for Error {
99 fn from(e: minijinja::Error) -> Self {
100 Error::Internal(format!("template error: {e}"))
101 }
102}