rustactix-web

How can I return a configured App in Actix-Web?


I'm using actix-web to create a httpserver with state/data embedded in it. But vscode show me that the create_app function has wrong arguments in its return value type definition App<AppState>:

pub struct App<T, B>
wrong number of type arguments: expected 2, found 1
expected 2 type argumentsrustc(E0107)

app.rs:

use crate::api;
use crate::model::DbExecutor;
use actix::prelude::Addr;
use actix_web::{error, http::Method, middleware::Logger, web, App, HttpResponse};

pub struct AppState {
    pub db: Addr<DbExecutor>,
}

pub fn create_app(db: Addr<DbExecutor>) -> App<AppState> {
    App::new().data(AppState { db }).service(
        web::resource("/notes/").route(web::get().to(api::notes))
    );
}

main.rs:

fn main() {
    HttpServer::new(move || app::create_app(addr.clone()))
        .bind("127.0.0.1:3000")
        .expect("Can not bind to '127.0.0.1:3000'")
        .start();
}

As return type of "service" method is "Self" which is type actix_web::App, I tried modify return type to App (without generic parameter) but still got error, what should I do?


Solution

  • First, App takes two generic type arguments, App<AppEntry, Body>, you've only given one.

    Second, AppState is not AppEntry.

    Third, instantiating App outside actix-web is hard, if not impossible, as the types you need from actix-web are not public.

    Instead, you should use configure to achieve the same, here is a simplified example:

    use actix_web::web::{Data, ServiceConfig};
    use actix_web::{web, App, HttpResponse, HttpServer};
    
    fn main() {
        let db = String::from("simplified example");
    
        HttpServer::new(move || App::new().configure(config_app(db.clone())))
            .bind("127.0.0.1:3000")
            .expect("Can not bind to '127.0.0.1:3000'")
            .run()
            .unwrap();
    }
    
    fn config_app(db: String) -> Box<dyn Fn(&mut ServiceConfig)> {
        Box::new(move |cfg: &mut ServiceConfig| {
            cfg.app_data(db.clone())
                .service(web::resource("/notes").route(web::get().to(notes)));
        })
    }
    
    fn notes(db: Data<String>) -> HttpResponse {
        HttpResponse::Ok().body(["notes from ", &db].concat())
    }
    

    Read more about ServiceConfig in the api documentation.