Which is better to implement asynchronous web requests in actix-web?

There seems to be two ways to implement asynchronous of handing web requests:

Method: "impl Future" ... and return by "future::ok" ...

#[get("/job/{job_id}")]
pub fn get_job(path: web::Path<(i64)>) -> impl Future<Item=HttpResponse, Error=actix_web::Error> {
let job_id = path.into_inner();
let job = jobs::load_job(job_id);
future::ok(HttpResponse::Ok().json(job))
}

Doc: https://github.com/actix/examples/blob/master/error_handling/src/main.rs

Method 2: "Box<dyn" and return by "Box::new"...

pub fn candidate_signup(params: web::Form) -> Box<dyn Future<Item = HttpResponse, Error = actix_web::Error>> {
println!("{} | {}", params.username, params.password);
Box::new(futures::future::ok::<_, actix_web::Error>(HttpResponse::Ok().finish()))
}

Doc: https://actix.rs/docs/handlers/

Can anyone tell me what are the differences and which one is better?

(Note: In this topic, I'm not talking about anything else like how the parameters are passed, or the functionality of the methods.)

Tokio's website has a good overview of the tradeoffs involved in the different ways of returning futures. Not Actix-specific, but should still be helpful.

2 Likes

IIRC, you can actual have your return type be impl Future<...> and still use Box::new.

Using Box allocates the memory for the future on the heap rather than the stack.

1 Like

When using a box, you pay a performance cost in exchange for convenience. Whenever possible I would use impl Future, and if you get errors because you're returning different types of futures in different branches, I recommend looking into Either, which allows combining them into one.

3 Likes