[question] Convert errors to user friendly errors
Is there a best practice method of converting a sqlx::Error::Database to a user friendly message. For example, when writing HTTP API, I have a create user route. When there's already a user with the email address given, the error returned is the constraint error:
duplicate key value violates unique constraint "users_email_key"
Is there an easy way to map these errors to a more user friendly error, something like "A user with that email address already exists"? This is the best I've come up with so far but it seems a bit verbose/awkward:
...
.execute(db)
.await
.map_err(|e| {
match e {
sqlx::Error::Database(e) => {
if let Some("23505") = e.code() {
return UserError::EmailTaken;
}
}
_ => {}
};
UserError::General(e)
})?;
This is perhaps slightly better:
match e {
sqlx::Error::Database(e) if e.column_name() == Some("email") => {
UserError::EmailTaken
}
_ => UserError::General(e),
}
I think we could stand to improve the ergonomics here but I'm not sure how I'd want it to handle.
Ah yea that is cleaner, however when I debug log the e, the column_name shows as None 😕
Oh, it might be e.constraint_name() == Some("email_unique") or something like that. You can switch it back to matching on the error code if you find that more reliable.
just an update i think as of today this should look something like:
match err {
sqlx::Error::RowNotFound => Err(Error::UserNotFound.into()),
sqlx::Error::Database(err)
if err.constraint() == Some("username_key") =>
{
Err(Error::UsernameTaken.into())
}
_ => Err(err.into()),
}