0

I want to register application level data when configuring Actix http server, but when I try to access the data in a request handler with HttpRequest::app_data() I always get None. The code below panics in the index request handler at the expect statement. It does work however if I use a String instead of my TestData struct.

What am I doing wrong?

My cargo.toml:

[...]

[dependencies]
actix-web = "3.0"
log = "0.4"
env_logger = "0.9"

My code:

use actix_web::{middleware, web, HttpRequest, Result, Responder, HttpResponse};
use actix_web::{App, HttpServer};
use std::sync::Arc;
#[macro_use]
extern crate log;
extern crate env_logger;


struct TestData {
  host: String
}

pub async fn index(req: HttpRequest) -> impl Responder {
  let td: &TestData = req.app_data().expect("Test data missing in request handler.");
  td.host.clone()
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
  std::env::set_var("RUST_LOG", 
                    format!("actix_server={log_level},actix_web={log_level}", 
                            log_level="DEBUG"));
  env_logger::init();

  let server_data = web::Data::new(
    TestData {
      host: "Dadada".to_string(),
    }
  );

  HttpServer::new(move || {
     App::new()
      .app_data(server_data.clone())
      .route("/", web::get().to(index))
      .wrap(middleware::Logger::default())
  })
  .bind("127.0.0.1:8080")?
  .run()
  .await
}

Jerboas86
  • 596
  • 4
  • 12
Markus
  • 2,412
  • 29
  • 28

1 Answers1

2

You need to specify the Data<T> type to app_data with turbo fish syntax.

pub async fn index(req: HttpRequest) -> impl Responder {
  let td: &TestData = req.app_data::<web::Data<TestData>>().expect("Test data missing in request handler.");

  td.host.clone()
}

If you take a look to HttpRequest::app_data defintion, you see that app_data needs this info to desambiguate the get call

pub fn app_data<T: 'static>(&self) -> Option<&T> {
        for container in self.0.app_data.iter().rev() {
            //Used here ------------------------\/
            if let Some(data) = container.get::<T>() {
                return Some(data);
            }
        }

        None
}

If you only give the compiler the td type (td: &TestData). Applying coercion, the compiler will infer a T which respects T: 'static bound, but it will not be the T (web::Data<TestData>) that you want.

Jerboas86
  • 596
  • 4
  • 12