Actix-web: It's hard to return `HttpServer` or `App<AppEntry, Body>` from a function

Created on 6 Nov 2019  路  7Comments  路  Source: actix/actix-web

For some reason, I have to return HttpServer from a function (say consume a Config struct and generate a HttpServer). But the type signature of HttpServer is REALLY HARD for me to return, or even possible. Tons of depending types are private.

Even worse, so as actix_Web::App. App::new will return App<AppEntry, Body>, where AppEntry is private also... So it is still impossible to return from my function...

Most helpful comment

This bug is still valid and I think it should still be open.

I think if you can assign a value to a variable in your program, you should also be able to return that value from a function.

All 7 comments

App is not designed to be used directly.

I ran into this recently because I wanted to parameterize and factor out the construction of App in my actix-web project for prod vs. test use-cases. I gave up and solved it with copy-pasta when I saw @fafhrd91 say not to bother when someone was trying to reconcile the middleware struct wrapping the type w/ them returning an App.

I accept that this might be his design intent but having to copy-pasta the App init for every test suite is a design fault even if it's intentional. This is the basic prelude to every #[test] that talks to the API:

    let conf = config::get_env();
    let dbexec = config::make_app_state(conf.db);
    let mut app = test::init_service(
        App::new()
            .data(AppState { db: dbexec.clone() })
            .configure(router::config_app),
    );

    let conn = dbexec.0.get().unwrap();

Is there something else I'm supposed to do here?

Finding that actix_web::Resource, actix_web::Scope are usable. So maybe I can return there types instead

This bug is still valid and I think it should still be open.

I think if you can assign a value to a variable in your program, you should also be able to return that value from a function.

I ran into the same issue and tried to use the example in the "Configure" section linked above. I can't get even this simple example to work. I've copied most of the code exactly, and added main from the same page, modified to use create_app:

use actix_service::ServiceFactory;
use actix_web::dev::{MessageBody, ServiceRequest, ServiceResponse};
use actix_web::{web, App, Error, HttpResponse};
use actix_web::HttpServer;

fn create_app() -> App<
    impl ServiceFactory<
        Config = (),
        Request = ServiceRequest,
        Response = ServiceResponse<impl MessageBody>,
        Error = Error,
    >,
    impl MessageBody,
> {
    App::new().service(
        web::scope("/app")
            .route("/index.html", web::get().to(|| HttpResponse::Ok())),
    )
}

#[actix_rt::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| create_app())
    .bind("127.0.0.1:8088")?
    .run()
    .await
}

Here's what I get:

[email protected] actix-config $ cargo check
    Checking actix-config v0.1.0 (/Users/dap/oxide/experiments/actix-config)
error[E0277]: the trait bound `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>: actix_service::IntoServiceFactory<_>` is not satisfied
  --> src/main.rs:23:5
   |
23 |     HttpServer::new(|| create_app())
   |     ^^^^^^^^^^^^^^^ the trait `actix_service::IntoServiceFactory<_>` is not implemented for `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>`
   |
   = help: the following implementations were found:
             <actix_web::app::App<T, B> as actix_service::IntoServiceFactory<actix_web::app_service::AppInit<T, B>>>
   = note: required by `actix_web::server::HttpServer::<F, I, S, B>::new`

error[E0277]: the trait bound `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>: actix_service::IntoServiceFactory<_>` is not satisfied
  --> src/main.rs:23:5
   |
23 |     HttpServer::new(|| create_app())
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `actix_service::IntoServiceFactory<_>` is not implemented for `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>`
   |
   = help: the following implementations were found:
             <actix_web::app::App<T, B> as actix_service::IntoServiceFactory<actix_web::app_service::AppInit<T, B>>>
   = note: required by `actix_web::server::HttpServer`

error[E0277]: the trait bound `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>: actix_service::IntoServiceFactory<_>` is not satisfied
  --> src/main.rs:24:6
   |
24 |     .bind("127.0.0.1:8088")?
   |      ^^^^ the trait `actix_service::IntoServiceFactory<_>` is not implemented for `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>`
   |
   = help: the following implementations were found:
             <actix_web::app::App<T, B> as actix_service::IntoServiceFactory<actix_web::app_service::AppInit<T, B>>>

error[E0277]: the trait bound `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>: actix_service::IntoServiceFactory<_>` is not satisfied
  --> src/main.rs:23:5
   |
23 | /     HttpServer::new(|| create_app())
24 | |     .bind("127.0.0.1:8088")?
   | |____________________________^ the trait `actix_service::IntoServiceFactory<_>` is not implemented for `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>`
   |
   = help: the following implementations were found:
             <actix_web::app::App<T, B> as actix_service::IntoServiceFactory<actix_web::app_service::AppInit<T, B>>>
   = note: required by `actix_web::server::HttpServer`

error[E0277]: the trait bound `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>: actix_service::IntoServiceFactory<_>` is not satisfied
  --> src/main.rs:25:6
   |
25 |     .run()
   |      ^^^ the trait `actix_service::IntoServiceFactory<_>` is not implemented for `actix_web::app::App<impl actix_service::ServiceFactory, impl actix_http::body::MessageBody>`
   |
   = help: the following implementations were found:
             <actix_web::app::App<T, B> as actix_service::IntoServiceFactory<actix_web::app_service::AppInit<T, B>>>

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.
error: could not compile `actix-config`.

To learn more, run the command again with --verbose.

Sorry if I'm doing something wrong but I can't get this to work.

https://actix.rs/docs/application/

Configure section

configure can't use middeware

Was this page helpful?
0 / 5 - 0 ratings

Related issues

joshsleeper picture joshsleeper  路  3Comments

cheolgyu picture cheolgyu  路  3Comments

naturallymitchell picture naturallymitchell  路  4Comments

volfco picture volfco  路  4Comments

yoshrc picture yoshrc  路  5Comments