Reputation: 5553
I found in the docs an example of how to create global state, protected by Mutex, shared among processing threads that is made available to all your route handlers. Perfect! However, I prefer to use attributes attached to my functions to wire up my route handlers. I do not know the syntax (if permitted) to use attributed functions and also pass in the global state.
Here is the example from the actix-web docs, from https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Data.html
use std::sync::Mutex;
use actix_web::{web, App};
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() {
let data = web::Data::new(Mutex::new(MyData{ counter: 0 }));
let app = App::new()
// Store `MyData` in application storage.
.register_data(data.clone())
.service(
web::resource("/index.html").route(
web::get().to(index)));
}
Notice how the route handler named index
is being passed the web::Data
.
Now here are some snippets of my code.
use actix_web::{get, App, HttpResponse, HttpServer, Responder};
pub mod request;
pub mod routes;
const SERVICE_NAME : &str = "Shy Rules Engine";
const SERVICE_VERSION : &str = "0.1";
#[get("/")]
fn index() -> impl Responder {
HttpResponse::Ok().body(format!("{} version {}", SERVICE_NAME, SERVICE_VERSION))
}
mod expression_execute {
#[post("/expression/execute")]
fn route(req: web::Json<ExpressionExecuteRequest>) -> HttpResponse {
// ... lots of code omitted ...
if response.has_error() {
HttpResponse::Ok().json(response)
}
else {
HttpResponse::BadRequest().json(response)
}
}
}
pub fn shy_service(ip : &str, port : &str) {
HttpServer::new(|| {
App::new()
.service(index)
.service(expression_execute::route)
})
.bind(format!("{}:{}", ip, port))
.unwrap()
.run()
.unwrap();
}
Notice how I am calling method App::service
to wire up my route handlers.
Also notice how my route handler does not receive global state (because I have not yet added it to my app). If I used a similar pattern as the docs using register_data
to create global App data, what changes do I make to my method signature, the get
and post
attributes and anything else so that I can pass that global state to the handler?
Or is it not possible using get
and post
attributes to gain access to global state?
Upvotes: 4
Views: 5137
Reputation: 13992
The two cases you listed really don't have much difference:
//# actix-web = "1.0.8"
use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use std::sync::Mutex;
const SERVICE_NAME : &str = "Shy Rules Engine";
const SERVICE_VERSION : &str = "0.1";
struct MyData {
counter: usize,
}
#[get("/")]
fn index(data: web::Data<Mutex<MyData>>) -> impl Responder {
let mut data = data.lock().unwrap();
data.counter += 1;
println!("Endpoint visited: {}", data.counter);
HttpResponse::Ok().body(format!("{} version {}", SERVICE_NAME, SERVICE_VERSION))
}
pub fn shy_service(ip : &str, port : &str) {
let data = web::Data::new(Mutex::new(MyData{ counter: 0 }));
HttpServer::new(move || {
App::new()
.register_data(data.clone())
.service(index)
})
.bind(format!("{}:{}", ip, port))
.unwrap()
.run()
.unwrap();
}
fn main() {
shy_service("127.0.0.1", "8080");
}
You can verify that it works by simply curl
the http endpoint. For multiple extractors, you'll have to use tuple:
#[post("/expression/execute")]
fn route((req, data): (web::Json<ExpressionExecuteRequest>, web::Data<Mutex<MyData>>)) -> HttpResponse {
unimplemented!()
}
Upvotes: 5