Search code examples
rustactix-webscylla

How passing ScyllaDB connection in Rust Actix


I have problems implement scylla-rust-driver on Rust Actix. I want just create simple CRUD with scyllaDb.

First i create struct for App Data

    struct AppState {
      scy_session: Session,
      app_name: String,
    }

Next i create Simple function

    #[get("/")] 
    async fn index(data: web::Data<AppState>) -> String {
       // I want to CRUD in this function with ScyllaDB
       let app_name = &data.app_name; // <- get app_name
       format!("Hello {}!", app_name) // <- response with app_name
    }

And finally main.rs is

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let session: Session = SessionBuilder::new()
        .known_node("localhost:9042")
        .user("username", "password")
        .build()
        .await
        .expect("Some error message");

    HttpServer::new(|| {
        App::new()
            .data(AppState {
                scy_session: session,
                app_name: String::from("Actix-web"),
            })
            .service(index)
    })
        .bind("127.0.0.1:8080")?
        .run()
        .await
}

But show error :

error[E0277]: the trait bound `Session: Clone` is not satisfied in `[closure@src/main.rs:27:21: 34:6]`
  --> src/main.rs:27:5
   |
27 |       HttpServer::new(|| {
   |  _____^^^^^^^^^^^^^^^_-
   | |     |
   | |     within `[closure@src/main.rs:27:21: 34:6]`, the trait `Clone` is not implemented for `Session`

How actually implement scylla-rust-db on Actix web ? Thanks a lot


Solution

  • There is nothing special with Session, as seen here https://github.com/scylladb/scylla-rust-driver/blob/main/examples/parallel-prepared.rs

    The solution is to wrap it in an Arc. We don't necessary need to do so ourselves as web::Data does this itself. Here is what I got.

    use actix_web::{web, App, HttpResponse, HttpServer, Responder};
    
    use scylla::{Session, SessionBuilder};
    
    struct AppState {
        scy_session: Session,
        app_name: String,
    }
    
    /// Use the `Data<T>` extractor to access data in a handler.
    async fn index(data: web::Data<AppState>) -> impl Responder {
        let app_name = &data.app_name; // <- get app_name
        HttpResponse::Ok().body(format!("Hello {}!", app_name))
    }
    
    #[actix_web::main]
    async fn main() -> std::io::Result<()> {
        let session: Session = SessionBuilder::new()
            .known_node("localhost:9042")
            .user("username", "passwor")
            .build()
            .await
            .expect("Some error message");
        let data = web::Data::new(AppState {
            scy_session: session,
            app_name: String::from("Actix-web"),
        });
    
        HttpServer::new(move || {
            App::new()
                .data(data.clone())
                .route("/", web::get().to(index))
        })
        .bind("127.0.0.1:8080")?
        .run()
        .await
    }
    

    See also: https://stackoverflow.com/a/67772754/1418750