paperclip-rs / paperclip

WIP OpenAPI tooling for Rust.
Apache License 2.0
887 stars 117 forks source link

Actix: Getting error when trying to use to_async #64

Closed glademiller closed 5 years ago

glademiller commented 5 years ago

It seems like I am probably missing something simple. This is the error I am getting

error[E0277]: the trait bound `fn(actix_web::data::Data<service::application::Application>, middleware::auth::UserData, actix_web::types::json::Json<models::query::Query>) -> paperclip_core::v2::actix::FutureWrapper<impl futures::future::Future> {service::handlers::execute_query::execute_query}: paperclip_core::v2::schema::Apiv2Operation<(actix_web::data::Data<service::application::Application>, middleware::auth::UserData, actix_web::types::json::Json<models::query::Query>), paperclip_core::v2::actix::FutureWrapper<impl futures::future::Future>>` is not satisfied
  --> src/service/application.rs:28:36
   |
28 |                 .route(web::post().to_async(handlers::execute_query))
   |                                    ^^^^^^^^ the trait `paperclip_core::v2::schema::Apiv2Operation<(actix_web::data::Data<service::application::Application>, middleware::auth::UserData, actix_web::types::json::Json<models::query::Query>), paperclip_core::v2::actix::FutureWrapper<impl futures::future::Future>>` is not implemented for `fn(actix_web::data::Data<service::application::Application>, middleware::auth::UserData, actix_web::types::json::Json<models::query::Query>) -> paperclip_core::v2::actix::FutureWrapper<impl futures::future::Future> {service::handlers::execute_query::execute_query}`
wafflespeanut commented 5 years ago

No, I have missed something simple apparently. There was a breaking rewrite lately which got rid of all of whatever #[api_v2_operation] was previously doing and moved to internal traits. The former had the luxury of ignoring function parameters whenever they won't serve any purpose in spec generation (such as Data<T> or middleware::*), whereas the latter doesn't and I forgot to implement the traits for these thingies after the rewrite (sigh).

I'll patch this up and release a patch version soon. Thanks for reporting this! :)

glademiller commented 5 years ago

Thanks for your hard work.

wafflespeanut commented 5 years ago

Hey @glademiller, I've added empty schema impls for actix types in 7199f534fff8e5f34f90cfe87ade981bc473449f. With that change, the only thing that would cause the above error is middleware::auth::UserData. If that's a type you own, then you can mark it with #[api_v2_schema(empty)] and the error should go away. Can you try plugging the plugin again?

Ploppz commented 5 years ago

I have a problem using the commit you mentioned (7199f53).

error[E0277]: the trait bound `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>: actix_service::IntoNewService<_>` is not satisfied
  --> src/bin/api_server.rs:46:5
   |
46 |     HttpServer::new(|| {
   |     ^^^^^^^^^^^^^^^ the trait `actix_service::IntoNewService<_>` is not implemented for `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>`
   |
   = note: required by `actix_web::server::HttpServer::<F, I, S, B>::new`

error[E0277]: the trait bound `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>: actix_service::IntoNewService<_>` is not satisfied
  --> src/bin/api_server.rs:46:5
   |
46 | /     HttpServer::new(|| {
47 | |         App::new()
48 | |             .wrap_api()
49 | |             .with_json_spec_at("/api")
50 | |             .route("/import_data_set", web::post().to_async(import_data_set))
51 | |     })
   | |______^ the trait `actix_service::IntoNewService<_>` is not implemented for `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>`
   |
   = note: required by `actix_web::server::HttpServer`

error[E0277]: the trait bound `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>: actix_service::IntoNewService<_>` is not satisfied
  --> src/bin/api_server.rs:52:10
   |
52 |         .bind((Ipv4Addr::LOCALHOST, PORT))
   |          ^^^^ the trait `actix_service::IntoNewService<_>` is not implemented for `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>`

error[E0277]: the trait bound `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>: actix_service::IntoNewService<_>` is not satisfied
  --> src/bin/api_server.rs:46:5
   |
46 | /     HttpServer::new(|| {
47 | |         App::new()
48 | |             .wrap_api()
49 | |             .with_json_spec_at("/api")
...  |
52 | |         .bind((Ipv4Addr::LOCALHOST, PORT))
53 | |         .expect(&format!("Can not bind to port {}", PORT))
   | |__________________________________________________________^ the trait `actix_service::IntoNewService<_>` is not implemented for `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>`
   |
   = note: required by `actix_web::server::HttpServer`

error[E0277]: the trait bound `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>: actix_service::IntoNewService<_>` is not satisfied
  --> src/bin/api_server.rs:54:10
   |
54 |         .run()
   |          ^^^ the trait `actix_service::IntoNewService<_>` is not implemented for `paperclip_actix::App<actix_web::app_service::AppEntry, actix_http::body::Body>`

Here is the relevant part of my code. Note that before both struct ImportDataSet and enum Message, I put:

#[api_v2_schema]
#[derive(Serialize, Deserialize)]

#[api_v2_operation]
fn import_data_set() -> impl Future<Item = HttpResponse, Error = Error> {
    // some code
}

fn main() {
    use std::net::Ipv4Addr;

    HttpServer::new(|| {
        App::new()
            .wrap_api()
            .with_json_spec_at("/api")
            .route("/import_data_set", web::post().to_async(import_data_set))
    })
        .bind((Ipv4Addr::LOCALHOST, PORT))
        .expect(&format!("Can not bind to port {}", PORT))
        .run()
        .unwrap();
}
wafflespeanut commented 5 years ago

@Ploppz Once .wrap_api() is called, the existing actix_web::App gets transformed to a wrapper from the plugin. Now, .build() method should be called to get the App back. Try using:

HttpServer::new(|| {
        App::new()
            .wrap_api()
            .with_json_spec_at("/api")
            .route("/import_data_set", web::post().to_async(import_data_set))
            .build()
    })
Ploppz commented 5 years ago

Sorry I missed that. Thanks!

glademiller commented 5 years ago

Sorry for the delayed response I've been away from a computer for the past little while. I annotated my UserData struct as requested and now have a different error in addition to the original. The new error is below and originates in my middleware which adds UserData to the extensions.

error[E0063]: missing fields `cyclic`, `data_type`, `description` and 9 other fields in initializer of `middleware::auth::UserData`
   --> src/middleware/auth.rs:203:37
    |
203 |         req.extensions_mut().insert(UserData {
    |                                     ^^^^^^^^ missing `cyclic`, `data_type`, `description` and 9 other fields
wafflespeanut commented 5 years ago

@glademiller Wait, that's not right. The code above appears to be using paperclip::api_v2_schema macro rather than paperclip::actix::api_v2_schema (the former is used by codegen, whereas the latter is used by the plugin). Could you try importing the macro directly like so:

use paperclip::actix::api_v2_schema;

#[api_v2_schema]
pub struct UserData {
...

And, did you enable the actix feature?

glademiller commented 5 years ago

You are correct I was using paperclip::api_v2_schema using actix worked great thank you.