3

I have a query which inserts the data of an user into the db. It works fine, but the users table has an unique index on the username, so when trying to create a row with a username already existing, it throws an error:

pub async fn create(user: UserRequest, pool: &PgPool) -> anyhow::Result<User> {
   let new_user = sqlx::query_as!(
       User,
       r#"
       INSERT INTO users (first_name, username)
       VALUES ($1, $2)
       RETURNING id, first_name, username
       "#,
       &user.first_name,
       &user.username,
   )
   .fetch_one(&pool.clone())
   .await?;
    
   Ok(User {
       id: new_user.id,
       first_name: new_user.first_name,
       username: new_user.username,
   })
}

&user is a function argument defined as:

pub struct UserRequest {
    pub first_name: String,
    pub username: String,
}

The endpoint using this function uses match to check if it's Ok(user) or anything else, and returns its response:

pub async fn create_user(
    user: web::Json<UserRequest>,
    pool: Data<PgPool>,
) -> impl Responder {
    let new_user = User::create(user.into_inner(), pool.get_ref()).await;
    match new_user {
        Ok(user) => HttpResponse::Ok().json(user),
        _ => HttpResponse::BadRequest().body(ERROR_MESSAGE),
    }
}

What can I do in order to capture that case, when there's an error because the row is trying to be duplicated? The case is I'd need to return a different HTTP status when that happens.

  • I will use comment instead of the answer since it is not really an answer. You can check this URL: https://www.lpalmieri.com/posts/error-handling-rust/. I'm nohow associated with book author, except that I own my copy of the book... but you can also read book online in the form of a blog. – zmilan Jul 20 '21 at 20:38

1 Answers1

5

You can check the error code using get_code.

match new_user {
    Ok(user) => HttpResponse::Ok().json(user),
    Err(err) if err.get_code() == "23505" {
    // returns unique constraint violation response.
    },
    _ => HttpResponse::BadRequest().body(ERROR_MESSAGE),
}

To make this work as @MichaelAnderson pointed out in the comments,

you'd need to change the return type of create to Result<User, sqlx::postgres::PgDatabaseError>, or instead of changing the return type of create, you could use anyhow::Error::downcast or its related functions to get back to a PgDatabaseError

styvane
  • 59,869
  • 19
  • 150
  • 156