2

Is there a way to make an actix-web route handler aware of a pre-computed heavy object, that is needed for the computation of result?

What I intend to do, in the end, is to avoid having to recompute my_big_heavy_object each time a request comes along, and instead compute it once and for all in main, there access it from the index method.

extern crate actix_web;
use actix_web::{server, App, HttpRequest};

fn index(_req: HttpRequest) -> HttpResponse {
    // how can I access my_big_heavy_object from here?
    let result = do_something_with(my_big_heavy_object);
    HttpResponse::Ok()
        .content_type("application/json")
        .body(result)
}

fn main() {
    let my_big_heavy_object = compute_big_heavy_object();

    server::new(|| App::new().resource("/", |r| r.f(index)))
        .bind("127.0.0.1:8088")
        .unwrap()
        .run();
}
Jivan
  • 21,522
  • 15
  • 80
  • 131
  • 2
    See the example regarding application shared state [in the actix documentation](https://actix.rs/docs/application/#state) – user25064 Jun 12 '18 at 14:28

1 Answers1

2

First, create a struct which is the shared state for your application:

struct AppState {
    my_big_heavy_object: HeavyObject,
}

It's better to create a context wrapper like this, rather than just using HeavyObject, so you can add other fields to it later if necessary.

A few objects in Actix will now need to interact with this, so you can make them aware of it by overriding the application state parameter in those types, for example HttpRequest<AppState>.

Your index handler can access the state through the HttpRequest's state property, and now looks like this:

fn index(req: HttpRequest<AppState>) -> HttpResponse {
    let result = do_something_with(req.state.my_big_heavy_object);
    HttpResponse::Ok()
        .content_type("application/json")
        .body(result)
}

When building the App, use the with_state constructor instead of new:

server::new(|| {
        let app_state = AppState { my_big_heavy_object: compute_big_heavy_object() };
        App::with_state(app_state).resource("/", |r| r.f(index))
    })
    .bind("127.0.0.1:8088")
    .unwrap()
    .run();

Note that the application state is assumed to be immutable. It sounds like you don't need any handlers to mutate it but if you did then you would have to use something like Cell or RefCell for interior mutability.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • state is not a field, but a method, so in this case it should be `req.state().my_big_heavy_object` instead of `req.state.my_big_heavy_object` – manonthemat Jun 13 '18 at 22:37