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

Parameters as struct implementing IntoParams for warp (and other frameworks) #150

Merged
merged 28 commits into from
Jun 18, 2022

Conversation

kellpossible
Copy link
Contributor

@kellpossible kellpossible commented May 30, 2022

TODO:

This work was sponsored by Arctoris.

@kellpossible
Copy link
Contributor Author

Figure out what to do about ParameterIn which is currently documented as an "internal trait". Perhaps this trait could also be derived?

As a solution to this I decided to implement #151 which will allow a container attribute for in to be specified which can optionally be used in place of relying on the ParamaterIn trait.

@kellpossible
Copy link
Contributor Author

kellpossible commented May 31, 2022

I ended up implementing the in attribute slightly differently, instead opting to have a named parameter called parameter_in because it allowed a simpler/cleaner parsing. Perhaps it might be worth a breaking change (or a deprecating change) for the field attribute to make it consistent too, because the current version favours write-ability over readability. From trying to implement parsing for an attribute named in I eventually figured out that in is probably not a valid Ident perhaps this is part of the reason why we ended up with the current implementation?

@kellpossible
Copy link
Contributor Author

@juhaku I think this PR is ready for review

@kellpossible kellpossible force-pushed the path-params-into-params branch from 977e94f to 39943cf Compare June 15, 2022 23:49
@kellpossible kellpossible force-pushed the path-params-into-params branch from 62fed6e to df5f5ae Compare June 16, 2022 00:01
@kellpossible
Copy link
Contributor Author

@juhaku I've rebased this to fix conflicts with #156

@juhaku
Copy link
Owner

juhaku commented Jun 17, 2022

I ended up implementing the in attribute slightly differently, instead opting to have a named parameter called parameter_in because it allowed a simpler/cleaner parsing. Perhaps it might be worth a breaking change (or a deprecating change) for the field attribute to make it consistent too, because the current version favours write-ability over readability. From trying to implement parsing for an attribute named in I eventually figured out that in is probably not a valid Ident perhaps this is part of the reason why we ended up with the current implementation?

The reason was to have as short syntax as possible but still being clear enough. Indeed I agree these 2 parsing syntaxes could be unified for clarity to the api consumers not having to guess the syntax.

The in is indeed reserved keyword in Rust thus does not play well with naming things directly same. But not sure at the moment whether it could be used like in = Path within the macro syntax. Maybe it could be tried.

I guess the next release will anyway be breaking release since I want to and need to make some changes to the actix-web support so it would work the same way that the type with IntoParams need to be defined in params(MyType) thus allowing users conditionally use params without IntoParams as well.

Copy link
Owner

@juhaku juhaku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super, 🥇 This is indeed pretty good base for getting IntoParams available to all the frameworks. Just some minor things to clarify :)

utoipa-gen/src/lib.rs Outdated Show resolved Hide resolved
utoipa-gen/src/lib.rs Outdated Show resolved Hide resolved
utoipa-gen/src/lib.rs Outdated Show resolved Hide resolved
/// `#[utoipa::path(params(...))]` attribute.
#[cfg_attr(feature = "debug", derive(Debug))]
#[derive(Default)]
struct Params<'p> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering is this extra Params type necessary?

utoipa-gen/src/path.rs Outdated Show resolved Hide resolved
@@ -27,10 +31,35 @@ use super::property::Property;
#[cfg_attr(feature = "debug", derive(Debug))]
pub enum Parameter<'a> {
Value(ParameterValue<'a>),
/// Identifier for a struct that implements `IntoParams` trait.
Struct(ExprPath),
#[cfg(any(feature = "actix_extras", feature = "rocket_extras"))]
TokenStream(TokenStream),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the TokenStream type was actually for that same purpse as now the Struct exists. The TokenStream will be later on used in extension code in similar manner <#struct as utoipa::IntoParams>::into_params() Im just wondering could these two types somehow be combined to avoid less fragmentation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is TokenStream a little too permissive for this? I'll admit I haven't taken a proper look at the actix/rocket side of the equation.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the purpose it is used in acitx-web extras https://github.com/juhaku/utoipa/blob/master/utoipa-gen/src/ext/actix.rs#L67 it is kind of necessary to have it to allow more than a expression path. Note it creates assert trait for the IntoParmas which could also be implemented here as well I think? 🤔

utoipa-gen/src/lib.rs Outdated Show resolved Hide resolved
Comment on lines 268 to 273
match &*style.to_string() {
"Path" => Ok(Self::Path),
"Query" => Ok(Self::Query),
"Header" => Ok(Self::Header),
"Cookie" => Ok(Self::Cookie),
_ => Err(Error::new(style.span(), EXPECTED_STYLE)),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we define one way how the parameter_in will be parsed, since now it is parsed with 2 different syntax one here with capitalized first letter, and in tuple syntax all lowercase. It would be better if there was only one way of doing things for clarity to the users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we change the other location to CamelCase that will be a breaking change, but it's also easier to recognise it as being one of the enum variants. I agree with you that it should be consistent, which direction would you like to take it?

Copy link
Contributor Author

@kellpossible kellpossible Jun 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering this library is already 1.0 I guess the aim is to reduce breaking changes where possible, perhaps I'll change this to lower case too?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can have it Pascal case. It will be breaking change but then it's going to be one. I consider the major release as a "how many mistakes have been done" and it can be increased according to the semver. But for sure it if it is possible to avoid breaking releases then it should be avoided as much as possible. But in this case it is fine for me. Then I can introduce other breaking changes as well with next release. So next release will then be 2.0.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay sounds good I'll try to share the parsing then for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juhaku how does it look now with 451ca01 ?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super that looks good

utoipa-gen/src/schema/into_params.rs Outdated Show resolved Hide resolved
help = "Try defining `#[into_params(names(...))]` over your type: {}", ident,
}
}
}
}
}

struct Param<'a>(&'a Field, Option<&'a String>);
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct FieldParamContainerAttributes<'a> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is pretty good idea to have possibility to define the style in struct level for all parameter fields, but after all since it is parameter specific attribute. Is it still possible to override this struct level style with style in parameter level with param(style = ...)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 284-292 in into_params.rs this file

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good

Co-authored-by: Juha Kukkonen <juha7kukkonen@gmail.com>
@kellpossible
Copy link
Contributor Author

The in is indeed reserved keyword in Rust thus does not play well with naming things directly same. But not sure at the moment whether it could be used like in = Path within the macro syntax. Maybe it could be tried.

@juhaku I did try that and I think it works, but it involves having a different name for the parameter in utoipa-gen or using r#in, felt a little hacky but I can try to do it if you think it's a good idea?

@juhaku
Copy link
Owner

juhaku commented Jun 17, 2022

The in is indeed reserved keyword in Rust thus does not play well with naming things directly same. But not sure at the moment whether it could be used like in = Path within the macro syntax. Maybe it could be tried.

@juhaku I did try that and I think it works, but it involves having a different name for the parameter in utoipa-gen or using r#in, felt a little hacky but I can try to do it if you think it's a good idea?

I think it can be parameter_in at least it is named same as the type is its clear what represents though. 🤔

parsing logic, this is a breaking change to use Pascal case for these:
`Path`, `Query`, `Header`, `Cookie`
Copy link
Owner

@juhaku juhaku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome 🏆

@juhaku juhaku merged commit 4b8435b into juhaku:master Jun 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants