Improve error types
Closed this issue · 0 comments
hdoordt commented
Currently, Gerust generates an Error
type in the db
crate, which is of the following form:
/// Errors that can occur as a result of a data layer operation.
#[derive(Error, Debug)]
pub enum Error {
/// General database error, e.g. communicating with the database failed
#[error("database query failed")]
DbError(anyhow::Error),
/// No record was found where one was expected, e.g. when loading a record by ID
#[error("no record found where one was expected")]
NoRecordFound,
#[error("validation failed")]
/// An invalid changeset was passed to a writing operation such as creating or updating a record.
ValidationError(validator::ValidationErrors),
}
In the generated entity modules (e.g. tasks
), sqlx::Error
s are converted directly into Errro::DbError
, which wraps an anyhow::Error
, thereby throwing away information about the cause of the error. Instead, the DbError
variant should wrap a sqlx::Error
directly.
Furthermore, the web
crate should expose another Error
enum, which among others, wraps a db::Error
in one of its variants and implements axum::IntoResponse
. For example:
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Database error")]
Database(#[from] server_db::Error),
// todo add other variants
}
impl IntoResponse for Error {
fn into_response(self) -> axum::response::Response {
match self {
Error::Database(db_error) => match db_error {
server_db::Error::NoRecordFound => StatusCode::NOT_FOUND.into_response(),
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
},
_ => StatusCode::INTERNAL_SERVER_ERROR.into_response()
}
}
}
This allows returning a Result<T, web::error::Error>
directly from route handlers, greatly improving ergonomics.