use std::{error, fmt}; use axum::{ http::StatusCode, response::{IntoResponse, Response}, }; // I'm making an effort to avoid `anyhow` here, as that crate is _enormously_ // complex (though very usable). We don't need to be overly careful about // allocations on errors in this app, so this is fine for most "general // failure" cases. type BoxedError = Box; // Returns a 500 Internal Server Error to the client. Meant to be used via the // `?` operator; _does not_ return the originating error to the client. #[derive(Debug)] pub struct Internal(Id, BoxedError); impl From for Internal where E: Into, { fn from(error: E) -> Self { let id = Id::generate(); Self(id, error.into()) } } impl fmt::Display for Internal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self(id, _) = self; writeln!(f, "internal server error")?; writeln!(f, "error id: {id}")?; Ok(()) } } impl IntoResponse for Internal { fn into_response(self) -> Response { let Self(id, error) = &self; eprintln!("pilcrow: [{id}] {error}"); (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response() } } pub type Id = crate::id::Id; #[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct InternalError; impl crate::id::Prefix for InternalError { fn prefix(&self) -> &'static str { "E" } } pub struct Unauthorized; impl IntoResponse for Unauthorized { fn into_response(self) -> Response { (StatusCode::UNAUTHORIZED, "unauthorized").into_response() } } pub struct NotFound(pub E); impl IntoResponse for NotFound where E: std::error::Error, { fn into_response(self) -> Response { let Self(response) = self; (StatusCode::NOT_FOUND, response.to_string()).into_response() } }