Need some help using axum with sqlx. Handler<_, _> is not satisfied error

Hi,

I am still learning Rust and to further my learning I am trying to build a simple project using axum and sqlx.

I am using the example here to get started.

I tried changing some of the code to do a basic SELET * FROM query but this leads to a compiler error.

async fn using_connection_pool_extractor(
    Extension(pool): Extension<PgPool>,
) -> Result<Vec<String>, (StatusCode, String)> {
    sqlx::query_scalar("select * from todos")
        .fetch_all(&pool)
        .await
        .map_err(internal_error)
}

I am not sure if I am returning the correct type and I am not sure how to figure that out. I basically want to get a response with the selected data.

Compiler gives me error[E0277] and mentions something about the Handler trait not being satisfied, but I am not sure if that is the actual problem.

error[E0277]: the trait bound `fn(Extension<Pool<sqlx::Postgres>>) -> impl Future<Output = Result<Vec<String>, (StatusCode, String)>> {using_connection_pool_extractor}: Handler<_, _>` is not satisfied
   --> src/main.rs:52:17
    |
52  |             get(using_connection_pool_extractor).post(using_connection_extractor),
    |             --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Handler<_, _>` is not implemented for `fn(Extension<Pool<sqlx::Postgres>>) -> impl Future<Output = Result<Vec<String>, (StatusCode, String)>> {using_connection_pool_extractor}`
    |             |
    |             required by a bound introduced by this call
    |
    = help: the trait `Handler<T, ReqBody>` is implemented for `axum::handler::Layered<S, T>`
note: required by a bound in `axum::routing::get`

Does anyone know what I am doing wrong?

Thanks

What is pool? It probably needs to be wrapped in an Arc.

I have replied in SO as well, but copying the response here for URLO users' reference:

Try with:

async fn using_connection_pool_extractor(
    Extension(pool): Extension<PgPool>,
) -> Result<axum::Json<Vec<String>>, (StatusCode, String)> {
    sqlx::query_scalar("select * from todos")
        .fetch_one(&pool)
        .await
        .map_err(internal_error)
}

The reason why is that there's no implementation of the IntoResponse trait for Vec<T>. Here's a longer answer by Axum's author: Axum error handling/trait question

pool is the connection pool for the database.

let db_connection_str = std::env::var("DATABASE_URL")
        .unwrap_or_else(|_| "postgres://postgres:postgres@localhost".to_string());

    // setup connection pool
    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect_timeout(Duration::from_secs(3))
        .connect(&db_connection_str)
        .await
        .expect("can connect to database");

I noticed the example is using fetch_one rather than fetch_all.

With fetch_all

async fn using_connection_pool_extractor(
    Extension(pool): Extension<PgPool>,
) -> Result<axum::Json<Vec<String>>, (StatusCode, String)> {
    sqlx::query_scalar("SELECT * FROM todos")
        .fetch_all(&pool)
        .await
        .map_err(internal_error)
}

I am getting the following compiler error.

the trait bound `axum::Json<Vec<String>>: Type<sqlx::Postgres>` is not satisfied
   --> src/main.rs:69:5
    |
69  |     sqlx::query_scalar("SELECT * FROM todos")
    |     ^^^^^^^^^^^^^^^^^^ the trait `Type<sqlx::Postgres>` is not implemented for `axum::Json<Vec<String>>`

Thanks. That got rid of the Handler error, but now I am getting the following compiler error.

the trait bound `axum::Json<Vec<String>>: sqlx::Decode<'_, sqlx::Postgres>` is not satisfied
the following other types implement trait `sqlx::Decode<'r, DB>`:
  <&'r [u8] as sqlx::Decode<'r, sqlx::Any>>
  <&'r [u8] as sqlx::Decode<'r, sqlx::Postgres>>
  <&'r serde_json::raw::RawValue as sqlx::Decode<'r, DB>>
  <&'r str as sqlx::Decode<'r, sqlx::Any>>
  <&'r str as sqlx::Decode<'r, sqlx::Postgres>>
  <() as sqlx::Decode<'r, sqlx::Postgres>>
  <(T1, T2) as sqlx::Decode<'r, sqlx::Postgres>>
  <(T1, T2, T3) as sqlx::Decode<'r, sqlx::Postgres>>
and 34 others
required because of the requirements on the impl of `for<'r> FromRow<'r, PgRow>` for `(axum::Json<Vec<String>>,)`rustcE0277
query_scalar.rs(82, 26): required by a bound in `QueryScalar::<'q, DB, O, A>::fetch_one`

Not sure what it is asking me to do or if it is giving the right error.

The return type of using_connection_pool_extractor needs to implement IntoResponse.

That is another thing you changed from the example. I am not sure how to explain this, but an example of how I managed to do it is here:

Note: impl IntoResponse for ServerTrans ( the return type for my Handler function ).

Thank you for the example.

Basically, the handler function only accepts things that implement the IntoResponse trait. So either I need to create my own type that implements IntoResponse and pass that in as the return type for the Result or use a type that already implements IntoResponse like axum::Json<Vec<String>> suggested by moy2010.

So if I try to use built in axum types that already implement IntoResponse, the problem will be converting the Result of sqlx::query into that type.

Hope I am understanding this correctly.

Yes, that's right. See

and the argument type for get

Correct. Try this then:

async fn using_connection_pool_extractor(
    Extension(pool): Extension<PgPool>,
) -> Result<axum::Json<Vec<String>>, (StatusCode, String)> {
    sqlx::query_scalar("SELECT * FROM todos")
        .fetch_all(&pool)
        .map(|todos| axum::Json(todos))
        .await
        .map_err(internal_error)
}

So that the returning value matches the signature.

Thank you both. I kinda understand how to use it now.

Just had to move the .await up because of a minor compiler error, but it works now.

async fn using_connection_pool_extractor(
    Extension(pool): Extension<PgPool>,
) -> Result<axum::Json<Vec<String>>, (StatusCode, String)> {
    sqlx::query_scalar("SELECT * FROM todos")
        .fetch_all(&pool)
        .await.map(|todos| axum::Json(todos))
        .map_err(internal_error)
}
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.