ilmoi
ilmoi

Reputation: 2534

Rust actix-web: the trait `Handler<_, _>` is not implemented

I've moved from using actix-web 3.x.x to 4.x.x. and the code that's been running perfectly fine before is now throwing this error:

the trait bound `fn(actix_web::web::Query<TweetParams>, actix_web::web::Data<Pool<Postgres>>) -> impl std::future::Future {tweets4}: Handler<_, _>` is not satisfied
  --> src/routes/all_routes.rs:74:14
   |
74 | pub async fn tweets4(
   |              ^^^^^^^ the trait `Handler<_, _>` is not implemented for `fn(actix_web::web::Query<TweetParams>, actix_web::web::Data<Pool<Postgres>>) -> impl std::future::Future {tweets4}`

After some googling it seems there is indeed a Handler trait in the actix ecosystem (however, not actix-web I think).

I can't figure out where I need to implement the trait. The error message seems to suggest that it's missing on the function itself, but my understanding is that you can only implement traits on structs and enums, not functions?

Here's the handler code:

#[get("/tweets4")]
pub async fn tweets4(
    form: web::Query<TweetParams>,
    pool: web::Data<PgPool>,
) -> Result<HttpResponse, HttpResponse> {
    let fake_json_data = r#"
    { "name": "hi" }
    "#;

    let v: Value = serde_json::from_str(fake_json_data)
        .map_err(|_| HttpResponse::InternalServerError().finish())?;

    sqlx::query!(
        r#"
        INSERT INTO users
        (id, created_at, twitter_user_id, twitter_name, twitter_handle, profile_image, profile_url, entire_user)
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
        "#,
        Uuid::new_v4(),
        Utc::now(),
        "3",
        "4",
        "5",
        "6",
        "7",
        v,
    )
        .execute(pool.as_ref())
        .await
        .map_err(|e| {
            println!("error is {}", e);
            HttpResponse::InternalServerError().finish()
        })?;

    Ok(HttpResponse::Ok().finish())
}

What am I getting wrong?

If helpful, the entire project is on github here.

Upvotes: 9

Views: 7440

Answers (3)

user983716
user983716

Reputation: 2082

I had a very similar issue. The root cause of the problem was that I forgot to use an async function. In short, When looking at the documentation at https://actix.rs/docs/response/#json-response, make sure to use async fn index(name: web::Path<String>) -> Result<impl Responder> and not fn index(name: web::Path<String>) -> Result<impl Responder>.

Upvotes: 8

Abulkhair Talapov
Abulkhair Talapov

Reputation: 21

If you still face the same error, another solution is just to switch to 1.0.8

Upvotes: 1

ilmoi
ilmoi

Reputation: 2534

After sufficient trial and error I discovered that:

  1. What the error is actually saying is that the return value is missing the necessary implementation, not the function itself (if you're a beginner like me it's not obvious from the error message...)
  2. More specifically, it seems actix didn't like the built-in HttpResponse error type and I had to replace with my own:
#[derive(Debug)]
pub struct MyError(String); // <-- needs debug and display

impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "A validation error occured on the input.")
    }
}

impl ResponseError for MyError {} // <-- key

#[get("/tweets4")]
pub async fn tweets4(
    form: web::Query<TweetParams>,
    pool: web::Data<PgPool>,
) -> Result<HttpResponse, MyError> {
    let fake_json_data = r#"
    { "name": "hi" }
    "#;

    let v: Value = serde_json::from_str(fake_json_data).map_err(|e| {
        println!("error is {}", e);
        MyError(String::from("oh no")) // <-- here
    })?;

    sqlx::query!(
        //query
    )
        .execute(pool.as_ref())
        .await
        .map_err(|e| {
            println!("error is {}", e);
            MyError(String::from("oh no")) // <-- and here
        })?;

    Ok(HttpResponse::Ok().finish())
}

Hope helps someone in the future!

Upvotes: 6

Related Questions