Comments (14)
Could you modify it to take them into account?
This seems like it is rocket specific feature if I'm not mistaken. It could be possible to add and can be done at some point :) But I am quite piled up with tasks at the moment so it wont be very top on the list unfortunately.
On the other hand, that #[form]
does similar functionality that is already supported with serde attributes. Serde support is general to all frameworks and thus is preferred over the framework specific things.
Also, what's the best way to use this
VecParam
generic type in a field, so that I don't have to duplicate the wholeFilterParams
type just for the doc spec (which can go out of sync with the real type used in the handler)?
This is an important question because many of the API types have fields that use generics.
Not sure do I understand your question correctly. But could not the VecParam
be just Vec<...>
? Nor is not the FilterParams
the type that is used as an argument to the fn my_handler(filter_params: FilterParams)
? I suppose that FilterParams
can be defined multiple times by adding it over multiple different functions.
params(
("filter_params" = FilterParams, description = "Filter parameters"),
)
Could you give an example of your your code like how you would use it or what is the case you are trying to implement if non of my nonsense helps 😂
from utoipa.
Thanks for your quick reply :)
But could not the VecParam be just Vec<...>?
Unfortunately not. This is a wrapper around Vec for the purpose of deserializing it from a comma-separated list (in a FromFormValue
impl), it's not possible to use Vec here. Btw, this is just one example, there are many others were generics are used in field types.
Nor is not the FilterParams the type that is used as an argument to the fn my_handler(filter_params: FilterParams)?
The handler argument is filter_params: Form<ListControlResultsFilterParams>
(using rocket's Form
).
I suppose that FilterParams can be defined multiple times by adding it over multiple different functions.
How do you mean? :)
What I want to avoid is having to duplicate most types that occur in the API just because they are generics or have generics in their fields.
Could you give an example of your your code
It's not so easy because it's confidential and Github still doesn't support confidential issues (that only the repo owner can see).
But it's basically like the code I wrote above, the VecParam
has to be used, and it is generic. And FilterParams
has to be a form.
from utoipa.
@juhaku Btw, regarding my filter_params
, it seems I can make it work by writing an isomorphic struct (using a monomorphized VecParamUuid
) that is only used in the utoipa
attributes.
Do I have to write a params
entry for every field of FilterParams
, like this?
params(
("ids" = Option<VecParamUuid>, query, style = Form, description = "ids"),
("archived" = Option<bool>, query, style = Form, description = "archived"),
("dueDateStart" = Option<i64>, query, style = Form, description = "dueDateStart"),
("dueDateEnd" = Option<i64>, query, style = Form, description = "dueDateEnd"),
("periodStart" = Option<String>, query, style = Form, description = "periodStart"),
("periodEnd" = Option<String>, query, style = Form, description = "periodEnd"),
)
)]
#[get("/results?<filter_params..>")]
Or can I write it like this?
params(
("filter_params" = FilterParams, query, style = Form, description = "Filter parameters"),
)
)]
#[get("/results?<filter_params..>")]
The VecParam
fields need to be parsed like this, how can I specify that in params(..)
? :)
https://swagger.io/docs/specification/serialization/
Another small question: Currently I'm doing Config::from("/api-doc/v1.json")
, how can I pass additional config params that are not part of the API spec, such as "tryItOutEnabled": false
, to disable the "Try it out" button for handlers?
https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
from utoipa.
@oliver-impero Sorry for late reply, been really busy lately leaving me freetime between zero and none.
Do I have to write a params entry for every field of FilterParams, like this?
This was actually the first ever plan I had in my mind what comes to parameters. And that is a valid way to describe the parameters. And to be honest it never crossed my mind that parameters could be described like this. 😂
#[derive(Serliaze, Deserialize, Component, Form)]
struct Params {
foo: Option<String>
}
//...
#[utoipa::path(
params(
("params" = Params, description = "Query Params")
)
)]
fn foo(params: Form<Params>) {...}
If that works thats brilliant though currently it indeed lacks a way to override the type and other configs for arguments in this form.
However how I intended the params
to be used is either like
params( ("ids" = Option<VecParamUuid>, query, style = Form, description = "ids"), ("archived" = Option<bool>, query, style = Form, description = "archived"), ("dueDateStart" = Option<i64>, query, style = Form, description = "dueDateStart"), ("dueDateEnd" = Option<i64>, query, style = Form, description = "dueDateEnd"), ("periodStart" = Option<String>, query, style = Form, description = "periodStart"), ("periodEnd" = Option<String>, query, style = Form, description = "periodEnd"), )
This approach is works fine with every framework. But also the <VecParamUuid>
currently cannot give correct type for the argument. If the VecParamUuid
is unnamed struct struct VecParamUuid(Vec<Uuid>);
then the utoipa
is able to tell that the type is actually Vec<Uuid>
and not VecParamUuid
. If the VecParamUuid
is named struct like seen below Utoipa is not able to tell that the type represented in OpenAPI should be Vec<Uuid>
. e.g.
struct VecParamUuid {
ids: Vec<Uuid>,
}
However the params(...)
section is only for declaring what's shown in the OpenAPI spec. So you could write the this way as well:
// .. derives omitted
struct MyActualParams {
ids: Option<VecParamUuid>,
}
//...
params(
("ids" = Option<[Uuid]>, query, style = Form, description = "ids"),
)
// ...
fn foo(params: From<MyActualParmas>) {...}
And it would work since the entries defined within params(....here...)
does not actually care about the type itself and does not make any type checks against the actual struct or object. It only uses the given type semantics of params and creates the OpenAPI operation parameters based on that. See the docs https://docs.rs/utoipa/1.0.2/utoipa/attr.path.html#params-attributes for more details but in short the type
in parameter entry can be in a format of:
ids = [Uuid]
making it Vec/slice of Uuid'sids = Option<[Uuid]>
making it optional Vec/slice of Uuid'sids = Uuid
making it Uuidids = Option<Uuid>
making it optional Uuid
But what comes to defining parameters with structs my end goal was to eventually have similar approach with IntoParams
trait that exists for actix-web framework. Example: https://docs.rs/utoipa/1.0.2/utoipa/derive.IntoParams.html And currently you can define the style
and other arguments for parameters Only within IntoParams
implementation or directly within entries of params(...)
section. But not in Component
as they had different purpose actually.
The style = Form
attribute controls how parameters are shown. You may find more information in the specification here: https://swagger.io/specification/#parameter-object just browse done a little to the table of Style Values. The default style
is controlled by the in
attribute where parameter is placed. And default to the array types (slice / vec) is Form
.
To get it represented as comma separated list you need to define style as Simple
("ids" = Option<[Uuid]>, query, style = Simple, description = "ids"),
And when it is possible to use IntoParmas or similar with rocket the idea that I had was ofcourse allow as much as code sharing as possible so that one could write something like this.
#[derive(Serialize, Deserialize, IntoParams)]
struct MyParams {
...
}
#[utoipa::path(...)]
fn foo(my_params: Path<MyParams>) {...}
#[utoipa::path(...)]
fn bar(my_params: Path<MyParams>) {...}
In above code the both of the endpoints would share same parameters which are also the actual parameters for the function and not duplicate parameter objects.
from utoipa.
Another small question: Currently I'm doing Config::from("/api-doc/v1.json"), how can I pass additional config params that are not part of the API spec, such as "tryItOutEnabled": false, to disable the "Try it out" button for handlers?
https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
At the moment it is not possible to to alter Swagger UI configurations aside of controlling the name
, url
or primary
fields of api doc url(s). It's in my plans to have it there but so far other features have been the priority since most of people are fine with the defaults. Just recently the configuration parameters where improved to support the oauth parameters by contributor. But eventually, yes, more granual control over Swagger UI configuration will be supported. :)
from utoipa.
Hm, this doesn't seem to work, it still expects me to define filter_params
even though I defined all constituents:
params(
("ids" = Option<VecParamUuid>, query, style = Form, description = "ids"),
("archived" = Option<bool>, query, style = Form, description = "archived"),
("dueDateStart" = Option<i64>, query, style = Form, description = "dueDateStart"),
("dueDateEnd" = Option<i64>, query, style = Form, description = "dueDateEnd"),
("periodStart" = Option<String>, query, style = Form, description = "periodStart"),
("periodEnd" = Option<String>, query, style = Form, description = "periodEnd"),
)
)]
#[get("/foo?<filter_params..>")]
pub fn foo(
executor: ApiKeyExecutor,
config: State<AppConfig>,
page_query: PaginationQuery,
filter_params: LenientForm<FilterParams>,
)
When trying to generate the API client, I get this error:
Exception in thread "main" org.openapitools.codegen.SpecValidationException: There were issues with the specification. The option can be disabled via validateSpec (Maven/Gradle) or --skip-validate-spec (CLI).
| Error count: 1, Warning count: 0
Errors:
-attribute paths.'/public-api/v1/foo'(get).parameters.[filter_params].schemas.#/components/schemas/FilterParams is missing
at org.openapitools.codegen.config.CodegenConfigurator.toContext(CodegenConfigurator.java:556)
at org.openapitools.codegen.config.CodegenConfigurator.toClientOptInput(CodegenConfigurator.java:583)
at org.openapitools.codegen.cmd.Generate.execute(Generate.java:433)
at org.openapitools.codegen.cmd.OpenApiGeneratorCommand.run(OpenApiGeneratorCommand.java:32)
at org.openapitools.codegen.OpenAPIGenerator.main(OpenAPIGenerator.java:66)
and in the browser:
Could not resolve reference: Could not resolve pointer: /components/schemas/FilterParams does not exist in document
How to make this work / how to specify in the attribute that it should ignore filter_params
?
Thanks! :)
Btw, in the generated doc, it doesn't seem to make it apparent when a param is optional, how can it be made visible that a param is optional (Option
)?
from utoipa.
How to make this work / how to specify in the attribute that it should ignore filter_params?
Thanks! :)
Oh, this is actually not possible with the current implementation. Quote from the docs below 👇
Utoipa is only able to parse parameter types for primitive types, String, Vec, Option or std::path::PathBuf type. Other function arguments are simply ignored.
And the <filter_params..>
wont be ignored since it is defined in the #[get(...)]
path macro. And this causes the issue you encounter. It will add the reference to FilterParams
as demonstrated with following code:
#[get("/foo?<filter_params..>")] pub fn foo( executor: ApiKeyExecutor, config: State<AppConfig>, page_query: PaginationQuery, filter_params: LenientForm<FilterParams>, <-- This will add the reference to FilterParams. )
And since FilterParams
is not #[derive(Component)]
and is not added to the OpenApi with #[openapi(components(FilterParams))]
thus not finding it from the generated OpenAPI as well. And really it should not be component though but it should not create reference either. Although it creates it now becuase the the #[get(...<filter_params..>)]
macro. This is something that needs special handling and some throughout thinking of possible solutions to get around this issue with rocket.
Btw, in the generated doc, it doesn't seem to make it apparent when a param is optional, how can it be made visible that a param is optional (Option)?
Hmm that's weird, the Option<...>
should make the parameter in the doc as optional. If the type is just the concrete type there will appear red *
infront and wont let users to try out the endpoint without filling the argument. When it is Option<...>
users can optionally fill the field in the Swagger UI.
from utoipa.
So the only workaround is to list each filter param manually in the url string and handler args?
from utoipa.
Yes, for time being it is unfortunately. This is something that need to be investigated and see whether it is possible and how much effort it would take to support the form style parameters.
from utoipa.
Could there be a way to support lists without wrapping it in a generic + aliases?
Something like this (status = 200, body = Vec<ApplicationData>),
from utoipa.
Yes they are supported if I understand your question right. For example the lists can be defined like so
(status = 200, body = [ApplicationData])
. Lists are wrapped in brackets. https://docs.rs/utoipa/1.1.0/utoipa/attr.path.html#responses-attributes
from utoipa.
@oliver-impero Update about this feature, see #222, I'm now working on this and the support should land in next 2.0.0 release :) Of course using master branch you will get it immediately when it's merged. 🙂
from utoipa.
Closing due inactivity.
from utoipa.
Something like this (status = 200, body = Vec),
With #408 The body can also support Vec<...>
types as well. This is because the parsing logic will be the same as used in ToSchema
and IntoParams
.
from utoipa.
Related Issues (20)
- Unit structs should include schema documentation
- OIDC Authorization token in cookie
- How to define multiple methods (GET/HEAD/OPTIONS) for same method
- Not working when using cookie authentication
- Generated openapi properties is not in order HOT 2
- Name clash for `Object`
- utopia-swagger-ui tainted by MPL-2 HOT 4
- generic enums fail to produce correct schemas for variants
- IntoParams does not respect `#[serde(flatten)]` and instead interprets it as an object HOT 1
- Is there any way to configure utoipa behind reverse proxy?
- Deserialising specification files fails everytime
- Add flexibility to `utoipa-swagger-ui` build process HOT 2
- Swagger UI returns 404 when renaming the package
- Better way of path registration
- Using #[schema(title = ...)] does not work for new type / tuple structs of type Vec<T>
- `ToResponse` `response` derive should be possible to namespace HOT 4
- Bug: bad schema for optional enums inside of named structs. HOT 1
- Feature request: Support serde rename_all_fields
- The proc-macro-error crate is end-of-life and unmaintained HOT 4
- What is schema value_type definition for nested Vec of struct HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from utoipa.