I have a small backend app written in Rust
using actix-web
. I want to have a function similar to the following.
async fn function(var: bool) -> impl Responder {
if var {
Redirect::to("link")
} else {
NamedFile::open_async("/file").await
}
}
I get the error :`if` and `else` have incompatible types expected `Redirect`, found future
.
I think this can probably be done by reading the file into a string and using HttpResponse
. But since NamedFile
implements Responder
, is it possible to make it work in this setting?
If I get rid of the if-else, each of these are valid return types, but the return types of an if-else statement must match. So, is it possible to maybe not use the if-else in this situation?
Edit: The linked solution doesn't work in this case. Changing the impl Responder to Box<dyn Responder>
causes the trait bounds to fail. I get the following error message:
the trait bound `std::boxed::Box<(dyn actix_web::Responder + 'static)>: actix_web::Responder` is not satisfied
Maybe it can be fixed, but I don't have enough experience with Rust generics to do it.
Dynamic dispatch cannot work with Responder
, but there are two other solutions.
The first is using Either
, that also implements Responder
by forwarding to the active variant:
use actix_web::Either;
async fn function(var: bool) -> impl Responder {
if var {
Either::Left(Redirect::to("link"))
} else {
Either::Right(NamedFile::open_async("/file").await)
}
}
A second option, as you said, is to convert them to HttpResponse
. They have different body types, so we also need to convert the bodies:
async fn function(var: bool, request: HttpRequest) -> HttpResponse {
if var {
Redirect::to("link")
.respond_to(&request)
.map_into_boxed_body()
} else {
NamedFile::open_async("/file")
.await
.respond_to(&request)
.map_into_boxed_body()
}
}
HttpRequest
is an extractor, so you can just have this parameter in your handler function.