Respond with either a Redirect or a NamedFile in actix-web

43 Views Asked by At

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.

1

There are 1 best solutions below

1
Chayim Friedman On BEST ANSWER

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.