Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conflicting implementations of utoipa::ParameterIn #132

Closed
1lutz opened this issue May 8, 2022 · 5 comments · Fixed by #156
Closed

Conflicting implementations of utoipa::ParameterIn #132

1lutz opened this issue May 8, 2022 · 5 comments · Fixed by #156
Assignees
Labels
bug Something isn't working

Comments

@1lutz
Copy link
Contributor

1lutz commented May 8, 2022

This code used to compile in version "0.1.2":

#[derive(Serialize, Deserialize, Component)]
struct WorkflowId(u64);

#[utoipa::path(get, path = "/workflow/{id}")]
async fn load_workflow(id: Path<WorkflowId>) {}

#[utoipa::path(delete, path = "/workflow/{id}")]
async fn delete_workflow(id: Path<WorkflowId>) {}

In the current version "1.0.2" the compilers yields

error[E0119]: conflicting implementations of trait `utoipa::ParameterIn` for type `WorkflowId`
  --> src/main.rs:12:35
   |
9  | async fn load_workflow(id: Path<WorkflowId>) {}
   |                                 ---------- first implementation here
...
12 | async fn delete_workflow(id: Path<WorkflowId>) {}
   |                                   ^^^^^^^^^^ conflicting implementation for `WorkflowId`
@juhaku
Copy link
Owner

juhaku commented May 8, 2022

This is indeed is unwanted behaviour caused by the new IntoParams functionality for actix-web. Thanks for noticing, I'll try to solve this one for the next release. But currently there is no cure for this, other than what comes to above code could also be written using type alias giving you same behaviour if there is no need to add any other custom logic to the workflow id via implementing traits etc.

type WorkflowId = u64;

#[utoipa::path(get, path = "/workflow/{id}")]
async fn load_workflow(id: Path<WorkflowId>) {}

#[utoipa::path(delete, path = "/workflow/{id}")]
async fn delete_workflow(id: Path<WorkflowId>) {}

@juhaku juhaku added the bug Something isn't working label May 8, 2022
@juhaku juhaku self-assigned this May 9, 2022
@supercmmetry
Copy link

Hi @juhaku, I'm having the same problem with query in actix. Using aliases doesn't seem to help.

@supercmmetry
Copy link

supercmmetry commented May 14, 2022

Maybe instead of creating impls for the struct itself we could do something like this

impl ParameterIn for WorkflowId_load_workflow {

}

impl ParameterIn for WorkflowId_delete_workflow {

}

Or, we could use monads instead to specify if the struct is part of a query/header/etc

Something like this:

type WorkflowId = u64;

#[utoipa::path(get, path = "/workflow/{id}")]
async fn load_workflow(id: Query<utoipa::Query<WorkflowId>>) {}

#[utoipa::path(delete, path = "/workflow/{id}")]
async fn delete_workflow(id: Path<utoipa::Path<WorkflowId>>) {}

Here the monads: utoipa::Query and utoipa::Path would wrap structs and impl ParameterIn appropriately for them.

@juhaku
Copy link
Owner

juhaku commented May 16, 2022

@supercmmetry @1lutz

Maybe instead of creating impls for the struct itself we could do something like this

impl ParameterIn for WorkflowId_load_workflow {

}

impl ParameterIn for WorkflowId_delete_workflow {

}

Or, we could use monads instead to specify if the struct is part of a query/header/etc

Something like this:

type WorkflowId = u64;

#[utoipa::path(get, path = "/workflow/{id}")]
async fn load_workflow(id: Query<utoipa::Query<WorkflowId>>) {}

#[utoipa::path(delete, path = "/workflow/{id}")]
async fn delete_workflow(id: Path<utoipa::Path<WorkflowId>>) {}

Here the monads: utoipa::Query and utoipa::Path would wrap structs and impl ParameterIn appropriately for them.

Yes, actually why not. There is a sides for each an every of those implementations. For the first one it is most transparent to the end users. However will create unnecessary duplicate code but that is not too big of an issue. And it is propably the simpliest implementation though.

The second is nice. I also considered someting like this since it would then provide nicely support for other frameworks as well. However not sure how willing peeps are to use the extra wrapper type for those.

Third option that I was thinking regarding this is to completely get rid of the ParameterIn trait that I introduced there but that is also a bit of a working progress. It might be that I need to implement the monads for other frameworks eventually though.

My current idea is to finish the enhanced generics first #108 and then tackle this one. The generics are half done so it only needs final squeeze when I just find time.

PS. sorry for late reply been really busy these days making me not too responsive.

@juhaku
Copy link
Owner

juhaku commented Jun 10, 2022

Fix for this has been released now here one can find docs relating to this feature https://docs.rs/utoipa/1.1.0/utoipa/derive.IntoParams.html#intoparams-attributes-for-into_params.

Here is modified example of one posted previously which now should work. Note there is now #[into_params] attribute added the the type which is used to give name for unnamed type in OpenAPI schema.

#[derive(Serialize, Deserialize, IntoParams)]
#[into_params(names("id"))]
struct WorkflowId(u64);

#[utoipa::path(get, path = "/workflow/{id}")]
async fn load_workflow(id: Path<WorkflowId>) {}

#[utoipa::path(delete, path = "/workflow/{id}")]
async fn delete_workflow(id: Path<WorkflowId>) {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: Released
Development

Successfully merging a pull request may close this issue.

3 participants