Actix-web: Official document data cause `App data is not configured, to configure use App::data()`

Created on 30 May 2019  ·  7Comments  ·  Source: actix/actix-web

Struct actix_web::web::Data Offcial document is actix_web::web::Data - Rust.

code example + http server

/*
~~~Cargo.toml
[package]
name = "actix-data-example"
version = "0.1.0"
authors = ["ncaq <[email protected]>"]
edition = "2018"

[dependencies]
actix-web = "1.0.0-rc"
~~~
 */

use actix_web::*;
use std::sync::Mutex;

struct MyData {
    counter: usize,
}

/// Use `Data<T>` extractor to access data in handler.
fn index(data: web::Data<Mutex<MyData>>) {
    let mut data = data.lock().unwrap();
    data.counter += 1;
}

fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        let data = web::Data::new(Mutex::new(MyData { counter: 0 }));
        App::new()
            // Store `MyData` in application storage.
            .data(data.clone())
            .service(web::resource("/index.html").route(web::get().to(index)))
    })
    .bind("0.0.0.0:3000")?
    .run()
}

But, It is failed.
I received message App data is not configured, to configure use App::data().

This simular problem posted on stack overflow.
rust - Actix-Web reports "App data is not configured" when processing a file upload - Stack Overflow

I found workaround, but it is not work.

/*
~~~Cargo.toml
[package]
name = "actix-data-example"
version = "0.1.0"
authors = ["ncaq <[email protected]>"]
edition = "2018"

[dependencies]
actix-web = "1.0.0-rc"
env_logger = "0.6.0"
~~~
 */

use actix_web::*;
use std::sync::*;

fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_web=trace");
    env_logger::init();

    HttpServer::new(|| {
        App::new()
            .wrap(middleware::Logger::default())
            .data(Mutex::new(ActixData::default()))
            .service(web::resource("/index/").route(web::get().to(index)))
            .service(web::resource("/create/").route(web::get().to(create)))
    })
    .bind("0.0.0.0:3000")?
    .run()
}

fn index(actix_data: web::Data<Mutex<ActixData>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

fn create(actix_data: web::Data<Mutex<ActixData>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    actix_data.lock().unwrap().counter += 1;
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

/// actix-webが保持する状態
#[derive(Debug, Default)]
struct ActixData {
    counter: usize,
}

This can escape App data is not configured.
But, ActixData is reset to default after about 30 seconds.

I do not know what is happening.
It is true that the code of the official document does not work.

I listen workaround it is not work too.

/*
~~~Cargo.toml
[package]
name = "actix-data-example"
version = "0.1.0"
authors = ["ncaq <[email protected]>"]
edition = "2018"

[dependencies]
actix-web = "1.0.0-rc"
env_logger = "0.6.0"
~~~
 */

use actix_web::*;
use std::sync::*;

fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_web=trace");
    env_logger::init();

    HttpServer::new(|| {
        let data = Arc::new(Mutex::new(ActixData::default()));
        App::new()
            .wrap(middleware::Logger::default())
            .data(data.clone())
            .service(web::resource("/index/").route(web::get().to(index)))
            .service(web::resource("/create/").route(web::get().to(create)))
    })
    .bind("0.0.0.0:3000")?
    .run()
}

fn index(actix_data: web::Data<Arc<Mutex<ActixData>>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

fn create(actix_data: web::Data<Arc<Mutex<ActixData>>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    actix_data.lock().unwrap().counter += 1;
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

/// actix-webが保持する状態
#[derive(Debug, Default)]
struct ActixData {
    counter: usize,
}

This data reset too.

Most helpful comment

I asked people in the rust-jp community to tell you the correct answer.

/*
~~~Cargo.toml
[package]
name = "actix-data-example"
version = "0.1.0"
authors = ["ncaq <[email protected]>"]
edition = "2018"

[dependencies]
actix-web = "1.0.0-rc"
env_logger = "0.6.0"
~~~
 */

use actix_web::*;
use std::sync::*;

fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_web=trace");
    env_logger::init();

    let data = Arc::new(Mutex::new(ActixData::default()));
    HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .data(data.clone())
            .service(web::resource("/index/").route(web::get().to(index)))
            .service(web::resource("/create/").route(web::get().to(create)))
    })
    .bind("0.0.0.0:3000")?
    .run()
}

fn index(actix_data: web::Data<Arc<Mutex<ActixData>>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

fn create(actix_data: web::Data<Arc<Mutex<ActixData>>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    actix_data.lock().unwrap().counter += 1;
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

/// actix-webが保持する状態
#[derive(Debug, Default)]
struct ActixData {
    counter: usize,
}

Anyway, I think that the official document which does not move should be corrected.
I do not know specifically how to fix it, but…

All 7 comments

I asked people in the rust-jp community to tell you the correct answer.

/*
~~~Cargo.toml
[package]
name = "actix-data-example"
version = "0.1.0"
authors = ["ncaq <[email protected]>"]
edition = "2018"

[dependencies]
actix-web = "1.0.0-rc"
env_logger = "0.6.0"
~~~
 */

use actix_web::*;
use std::sync::*;

fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_web=trace");
    env_logger::init();

    let data = Arc::new(Mutex::new(ActixData::default()));
    HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .data(data.clone())
            .service(web::resource("/index/").route(web::get().to(index)))
            .service(web::resource("/create/").route(web::get().to(create)))
    })
    .bind("0.0.0.0:3000")?
    .run()
}

fn index(actix_data: web::Data<Arc<Mutex<ActixData>>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

fn create(actix_data: web::Data<Arc<Mutex<ActixData>>>) -> HttpResponse {
    println!("actix_data: {:?}", actix_data);
    actix_data.lock().unwrap().counter += 1;
    HttpResponse::Ok().body(format!("{:?}", actix_data))
}

/// actix-webが保持する状態
#[derive(Debug, Default)]
struct ActixData {
    counter: usize,
}

Anyway, I think that the official document which does not move should be corrected.
I do not know specifically how to fix it, but…

in original example you store different types.

fixed in master

Sorry to bother you all I have a similar issue I read the specs and I tried the outside arc clone.

I upgraded my application from 0.5.x to 1.0.9 and I ran into a similar issue.

actix = "0.8.3"
actix-web = "1.0.8"
actix-cors = "0.1.*"
pub trait ApiEndPoints {
    fn register_endpoints(config: &mut web::ServiceConfig) -> &mut web::ServiceConfig;
}

pub struct AppState {
    db: Addr<DbExecutor>,
    coap_client: Addr<CoAP>,
    send_email: Addr<SendEmail>,
    logger: Addr<LogActor>,
    qr_code: Addr<QrCodeActor>,
    image: Addr<ImageActor>,
    config: Arc<RwLock<HashMap<String, String>>>,
}

fn main() {
    dotenv().ok();
    ::std::env::set_var("RUST_LOG", "actix_web=error");
    env_logger::init();

    let config: Arc<RwLock<HashMap<String, String>>> = Arc::new(RwLock::new(HashMap::new()));

    ......

    let data = web::Data::new(Mutex::new(AppState {
        db: addr_db.clone(),
        coap_client: addr_coap.clone(),
        send_email: addr_email.clone(),
        qr_code: addr_qr_code.clone(),
        config: config.clone(),
        logger: addr_logger_app_state.clone(),
        image: addr_image.clone()
    }));

    HttpServer::new(move || {
        let app = App::new()
            .wrap(middleware::Logger::default())
            .wrap(
                Cors::new()
                    .allowed_methods(vec!["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"])
                    .max_age(3600)
            )
            .configure(|mut service| {
                let mut service = domain_model::evse_resource::endpoints::EvseResourceApi::register_endpoints(&mut service);
                let mut service = domain_model::user::endpoints::UserApi::register_endpoints(&mut service);
                let service = domain_model::charging_process::endpoints::ChargingApi::register_endpoints(&mut service);
            }).register_data(data.clone());

        app
    })
    .bind(api_server_address.clone())
    .unwrap()
    .start();

    println!("Started http server: {}", api_server_address.clone());
    let _ = sys.run();
}

as you can see the "move" as well as the Arc + Mutex do exist since

 web::Data::new(T) -> Data<T>(Arc<T>);

I still get the error message:

App data is not configured, to configure use App::data()

I am in hour 9 of coding so probably I am missing something obvious.

edit

got the problem. registered function needs to have the correct signature as well. I appologize if I caused any inconvenience. Maybe it's useful for someone else afterwards.

from:

fn create(
        (state, params): (web::Data<AppState>, Json<CreateUserRequest>),
    ) -> impl Future<Item=HttpResponse, Error=HttpResponse> {

to:

fn create(
        (state, params): (web::Data<Arc<Mutex<AppState>>>, Json<CreateUserRequest>),
    ) -> impl Future<Item=HttpResponse, Error=HttpResponse> {

I wasn't counting on this kind of resolve mechanism, I am also not quite sure why it works that way since the data is a tuple pushed on a vector of pointers but there are probably some good reasons for that. However there maybe is a better way of hinting possible mistakes. Maybe something like "no data for this route was found, please check App::data and the according method signature"

Anyhow I know talks is cheap. Thank you for your work.

I dont know thy this issue is closed it still continues I had to use lazy-static to initialize my data because actix-web doesnt simply work

@NikosEfthias i'm sure we can help you. Can you provide us a code snippet here or in the gitter chat so we can check what's going on.

@robjtede The issue was scoped configurations could not use the global app_dataI had to pass data of their own.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

icommit picture icommit  ·  3Comments

volfco picture volfco  ·  4Comments

Dadibom picture Dadibom  ·  4Comments

fafhrd91 picture fafhrd91  ·  5Comments

zhaobingss picture zhaobingss  ·  4Comments