Skip to main content

max / makenotwork

1.5 KB · 44 lines History Blame Raw
1 use axum::http::StatusCode;
2 use axum::response::{IntoResponse, Response};
3
4 #[derive(Debug, thiserror::Error)]
5 pub enum Error {
6 #[error("not found")]
7 NotFound,
8 #[error("bad request: {0}")]
9 BadRequest(String),
10 #[error(transparent)]
11 Db(#[from] sqlx::Error),
12 #[error(transparent)]
13 Other(#[from] anyhow::Error),
14 }
15
16 impl IntoResponse for Error {
17 fn into_response(self) -> Response {
18 // Client errors carry their (already user-facing) message; server errors
19 // are logged in full but return a generic body so internal detail (SQL
20 // text, anyhow chains, file paths) never leaks to the client.
21 let (status, message) = match &self {
22 Error::NotFound => (StatusCode::NOT_FOUND, "not found".to_string()),
23 Error::BadRequest(m) => (StatusCode::BAD_REQUEST, m.clone()),
24 Error::Db(e) => {
25 tracing::error!(error = %e, "internal db error");
26 (
27 StatusCode::INTERNAL_SERVER_ERROR,
28 "internal server error".to_string(),
29 )
30 }
31 Error::Other(e) => {
32 tracing::error!(error = format!("{e:#}"), "internal error");
33 (
34 StatusCode::INTERNAL_SERVER_ERROR,
35 "internal server error".to_string(),
36 )
37 }
38 };
39 (status, axum::Json(serde_json::json!({ "error": message }))).into_response()
40 }
41 }
42
43 pub type Result<T> = std::result::Result<T, Error>;
44