rust 无法将tokio-postgres池连接传递到Axum处理程序

3lxsmp7m  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(208)

我是Rust的新手我试图创建一个tokio-postgres连接池到一个处理程序,它应该使用连接填充数据库表。我使用deadpool-postgres,它似乎创建了池。问题是我无法将池传递给处理程序。
下面是与问题相关的代码:

use axum::{
    extract::State,
    routing::{get, post},
    Router,
    http::{Response, StatusCode},
    extract::Form,
    response::{IntoResponse, Redirect}
    };
use std::{convert::Infallible, fs, net::SocketAddr};
use tower_http::cors::{Any, CorsLayer};
use tokio_postgres::NoTls;
use deadpool_postgres::{Config, ManagerConfig, Pool, RecyclingMethod};

#[derive(Clone)]
struct AppState {
    db_pool: Pool
}

impl  AppState {
    async fn make_pool() -> Self {
        let mut config = Config::new();
        
        config.user = Some("postgres".to_string());
        config.password = Some("postgres".to_string());
        config.dbname = Some("localhost".to_string());
        config.host = Some("localhost".to_string());
        config.port = Some(5432);
        config.manager = Some(ManagerConfig { recycling_method: RecyclingMethod::Fast });
        
        let pool = config.create_pool(None, NoTls).unwrap();
        pool.resize(15);
        AppState {
            db_pool: pool,
        }
    }
}
 

async fn handle_form(Form(data): Form<FormData>, async fn handle_form(Form(data): Form<FormData>, State(client): State<AppState>) -> Result<Redirect, PoolError> {
    println!("->>\thandle_form__handler called");

    let conn = client.db_pool.get().await.unwrap();

    let values = (&data.nome, &data.cognome, &data.email);

    let query = "INSERT INTO users (nome, cognome, email) VALUES ($1, $2, $3)";
    if let Err(e) = conn.execute(query, &[&values.0, &values.1, &values.2])
        .await.map_err(|e| Into::<deadpool_postgres::PoolError>::into(e)) {
        eprintln!("error executing query: {}", e);
        return Err(e.into());
    }
    
    Ok(Redirect::to("/form/success/"))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {

    let client = AppState::make_pool().await;

    let cors = CorsLayer::new().allow_origin(Any);

    let app = Router::new()
        .route("/", get(index_handler))
        .route("/about/", get(about_handler))
        .route("/form/", get(form_handler))
        .route("/form/submit-form/", post(handle_form))
        .route("/form/success/", get(success_handler))
        .with_state(client)
        .layer(cors);
    
    let addr = SocketAddr::from(([127, 0, 0, 1], 8000));
    println!("listening on {}", addr);
        
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();

    Ok(())
}

报告的错误为:

error[E0277]: the trait bound `fn(Form<FormData>, State<AppState>) -> impl Future<Output = Result<Redirect, deadpool::managed::errors::PoolError<tokio_postgres::Error>>> {handle_form}: Handler<_, _, _>` is not satisfied
   --> src/main.rs:85:43
    |
85  |         .route("/form/submit-form/", post(handle_form))
    |                                      ---- ^^^^^^^^^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(Form<FormData>, State<AppState>) -> impl Future<Output = Result<Redirect, deadpool::managed::errors::PoolError<tokio_postgres::Error>>> {handle_form}`
    |                                      |
    |                                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S, B>`:
              <Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
              <MethodRouter<S, B> as Handler<(), S, B>>
note: required by a bound in `post`
   --> /home/bontxa/.cargo/registry/src/github.com-1ecc6299db9ec823/axum-0.6.18/src/routing/method_routing.rs:407:1
    |
407 | top_level_handler_fn!(post, POST);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `post`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

为了解决这个错误,我修改了这一行:

async fn handle_form(Form(data): Form<FormData>, State(client): State<AppState>) -> Result<Redirect, PoolError>

在:

async fn handle_form(Form(data): Form<FormData>, State(client): State<AppState<Pool>>) -> Result<Redirect, PoolError>

但现在新的错误是:

error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
  --> src/main.rs:57:71
   |
57 | async fn handle_form(Form(data): Form<FormData>, State(client): State<AppState<Pool>>) -> Result<Redirect, PoolError> {
   |                                                                       ^^^^^^^^------ help: remove these generics
   |                                                                       |
   |                                                                       expected 0 generic arguments
   |
note: struct defined here, with 0 generic parameters
  --> src/main.rs:26:8
   |
26 | struct AppState {
   |        ^^^^^^^^

这是我的Cargo.toml依赖部分:

[dependencies]
axum = "0.6.18"
tokio = { version = "1.28", features = ["full"] }
tokio-postgres = { version = "0.7.8", features = ["with-uuid-0_8"] }
tower-http = { version = "0.4.0", features = ["cors"] }
serde = { version = "1.0.162", features = ["derive"] }
deadpool-postgres = "0.10.5"

我也试过用“Extension”代替“State”,但情况是一样的。

41zrol4v

41zrol4v1#

deadpool::managed::errors::PoolError应转换为其他可以转换为响应的错误类型。

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use serde_json::json;
use thiserror::Error;

/// # ApiError
#[derive(Debug, Error)]
pub enum ApiError {
    #[error(transparent)]
    DbError(#[from] sea_orm::DbErr),
    #[error("not found")]
    NotFound,
}

impl IntoResponse for ApiError {
    fn into_response(self) -> Response {
        let status = match self {
            ApiError::NotFound => StatusCode::NOT_FOUND,
            _ => StatusCode::BAD_REQUEST,
        };
        let body = Json(json!({
            "error": self.to_string(),
        }));
        (status, body).into_response()
    }
}

full demo code

相关问题