juhaku / utoipa Goto Github PK
View Code? Open in Web Editor NEWSimple, Fast, Code first and Compile time generated OpenAPI documentation for Rust
License: Apache License 2.0
Simple, Fast, Code first and Compile time generated OpenAPI documentation for Rust
License: Apache License 2.0
I've noticed it's fairly easy to forget to add things to the macros -- for example I generated an incorrect swagger doc (my fault, not the tools) by leaving out a body = SomeBodyType
.
In some future version of this tool it would be nice to have this be a bit more foolproof and if body isn't specified it could assume the body is the return type of the annotated function. This leaves one less place where the actual source code and generated swagger docs could diverge. If someone did want to (or needed to) override that behavior they could provide the body in the macro as usual.
I know it might get tricky with the different return codes -- maybe only for 200. IME our return types from the handlers have always corresponded directly to the response we've specified in the swagger doc.
Thoughts?
It seems the the utoipa::path does not take into account the fact actix route proc_macros can have additional attributes, I discovered it when attempting to use the wrap attribute, but it seems to cause issue with any attribute or more specifically the ,
used to add additional attributes
Take the route:
/// Get Todo by given todo id.
///
/// Return found `Todo` with status 200 or 404 not found if `Todo` is not found from shared in-memory storage.
#[utoipa::path(
responses(
(status = 200, description = "Todo found from storage", body = Todo),
(status = 404, description = "Todo not found by id", body = TodoError)
),
params(
("id", description = "Unique storage id of Todo")
)
)]
#[get("/todo/{id}")]
pub(super) async fn get_todo_by_id(id: Path<i32>, todo_data: Data<TodoData>) -> impl Responder {
let todos = todo_data.todos.lock().unwrap();
let id = id.into_inner();
match todos.get_one(id) {
Ok(todo) => todo.response(),
Err(error) => error.response(),
}
}
And lets say we wanted to add a middleware with the wrap attribute:
/// Get Todo by given todo id.
///
/// Return found `Todo` with status 200 or 404 not found if `Todo` is not found from shared in-memory storage.
#[utoipa::path(
responses(
(status = 200, description = "Todo found from storage", body = Todo),
(status = 404, description = "Todo not found by id", body = TodoError)
),
params(
("id", description = "Unique storage id of Todo")
)
)]
#[get("/todo/{id}", wrap = "ApiKeyAuthenticator")]
pub(super) async fn get_todo_by_id(id: Path<i32>, todo_data: Data<TodoData>) -> impl Responder {
let todos = todo_data.todos.lock().unwrap();
let id = id.into_inner();
match todos.get_one(id) {
Ok(todo) => todo.response(),
Err(error) => error.response(),
}
}
It will cause a compiler error:
error: unexpected token
--> src\controllers\todo.rs:189:19
|
189 | #[get("/todo/{id}", wrap = "ApiKeyAuthenticator")]
| ^
vs without the utoipa proc_macro
#[get("/todo/{id}", wrap = "ApiKeyAuthenticator")]
pub(super) async fn get_todo_by_id(id: Path<i32>, todo_data: Data<TodoData>) -> impl Responder {
let todos = todo_data.todos.lock().unwrap();
let id = id.into_inner();
match todos.get_one(id) {
Ok(todo) => todo.response(),
Err(error) => error.response(),
}
}
Compiling playground-api v0.1.0 (C:\Users\bfall\Development\Rust\playground-api)
Finished dev [unoptimized + debuginfo] target(s) in 3.12s
#[derive(Deserialize, Serialize, utoipa::Component)]
#[serde(rename_all = "lowercase")]
pub enum MyType {
CaseOne,
CaseTwo,
}
yields
unexpected rename rule, expected one of: \"lowercase\", \"UPPERCASE\", \"Pascal\", \"camelCase\", \"snake_case\", \"SCREAMING_SNAKE_CASE\", \"kebab-case\", \"SCREAMING-KEBAB-CASE\"
In a struct that derives Component
:
error: expected at least one angle bracket argument but was 0
|
29 | pub ids: Option<VecParam<uuid::Uuid>>,
| ^^^^
I have some structs that contain types from chrono and rust_decimal. Those types give errors in the Swagger UI.
For example:
Could not resolve reference: Could not resolve pointer: /components/schemas/DateTime does not exist in document
Could not resolve reference: Could not resolve pointer: /components/schemas/Decimal does not exist in document
What is the proper way to handle these types?
I have a function which returns keys/values as Strings:
{
"key": "value",
"key2": "value2",
"key3": null
}
How can I represent this as a response body? I want to do something like
/// Get all application options
///
/// Get a list of all application options from the database
#[utoipa::path(
get,
path = "/options",
responses(
(status = 200, description = "Sucessfully returned all application options", body = [Map<String, Option<String>>])
)
)]
How can I add a custom API introduction text here (using markdown)? I tried with a doc comment (using #[doc = include_str!("API-Intro.md")]
) for my main ApiDoc
struct that has #[derive(OpenApi)]
, but the doc comment seems to be ignored by the generator, any idea why?
How can I specify the html <title>
for the generated doc? :)
Tracking issue for enhanced integration for rocket framework similar to actix_extras. Currently rocket framework is supported same way as warp or tide where all documentation must be provided with utoipa::path
path attribute macro, which means that rockets own macros cannot be "reused" in utoipa to generate the documentation.
Possibly changing list of actions:
Warp has the function https://docs.rs/warp/latest/warp/filters/query/fn.query.html which accepts query parameters in the form of a type that implements DeserializeOwned
. It would be good if we could plop this into params
instead of needing to respecify them manually. Perhaps https://docs.rs/utoipa/1.0.2/utoipa/derive.IntoParams.html could be generalised to fill this role?
Hi,
when using utoipa-swagger-ui
with rocket 0.4.10, I'm getting an error:
error[E0277]: the trait bound `Vec<Route>: std::convert::From<SwaggerUi>` is not satisfied
--> web/src/cli/web.rs:486:13
|
484 | rocket.mount(
| ----- required by a bound introduced by this call
485 | "/",
486 | SwaggerUi::new("/swagger-ui/<_..>").url("/api-doc/openapi.json", ApiDocV1::openapi()),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<SwaggerUi>` is not implemented for `Vec<Route>`
|
= help: the following implementations were found:
<Vec<T, A> as std::convert::From<VecDeque<T, A>>>
<Vec<T, A> as std::convert::From<std::boxed::Box<[T], A>>>
<Vec<T> as std::convert::From<&[T]>>
<Vec<T> as std::convert::From<&mut [T]>>
and 9 others
= note: required because of the requirements on the impl of `Into<Vec<Route>>` for `SwaggerUi`
note: required by a bound in `rocket::Rocket::mount`
--> /usr/src/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.4.10/src/rocket.rs:515:21
|
515 | pub fn mount<R: Into<Vec<Route>>>(mut self, base: &str, routes: R) -> Self {
| ^^^^^^^^^^^^^^^^ required by this bound in `rocket::Rocket::mount`
I see that utoipa-swagger-ui
depends on rocket 0.5.0-rc.1:
utoipa/utoipa-swagger-ui/Cargo.toml
Line 22 in 6cec102
Is it still possible to use it with rocket 0.4.10 somehow?
I tried
[patch.crates-io]
rocket = "0.4.10"
to replace the dependency, but I'm still getting the same error.
Updating crates.io index
error: failed to select a version for the requirement utoipa = "^1.0.2"
candidate versions found which didn't match: 0.2.0, 0.1.2, 0.1.1, ...
location searched: crates.io index
Cargo.toml
[dependencies]
axum = "0.5.5"
hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1.17", features = ["full"] }
tower = "0.4"
utoipa = "1.0.2"
utoipa-gen = "1.0.2"
utoipa-swagger-ui = "1.0.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
env_logger = "0.9.0"
log = "0.4"
Same issue as #152 but with body
in responses
#[utoipa::path(
responses(
(status = 200, body = response::WillNotWork),
),
)]
Tried on master.
For some reason (bug?), only primitive component fields seem to retain their doc comments (but not fields that are custom types/newtypes), e.g.:
Using serde_json::from_str
, the properties
of components
are not deserialized. See the example below, where an openapi spec is serialized and then deserialized, loosing component properties in the process.
use utoipa::openapi::{
schema::{ComponentType, ComponentsBuilder, ObjectBuilder, PropertyBuilder},
security::SecurityScheme,
OpenApi, {Info, OpenApiBuilder, Paths},
};
fn main() {
let openapi = OpenApiBuilder::new()
.info(Info::new("", "1.0.0"))
.paths(Paths::new())
.components(Some(
ComponentsBuilder::new()
.components_from_iter(vec![(
"Comp",
ObjectBuilder::new()
.property(
"name",
PropertyBuilder::new().component_type(ComponentType::String),
)
.required("name"),
)])
.security_scheme("TLS", SecurityScheme::MutualTls { description: None })
.build(),
))
.build();
let serialized_openapi = serde_json::to_string(&openapi).unwrap();
println!("{}", serialized_openapi);
let deserialized_openapi: OpenApi = serde_json::from_str(serialized_openapi.as_str()).unwrap();
println!("{}", serde_json::to_string(&deserialized_openapi).unwrap());
}
{"openapi":"3.0.3","info":{"title":"","version":"1.0.0"},"paths":{},"components":{"schemas":{"Comp":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}},"securitySchemes":{"TLS":{"type":"mutualTLS"}}}}
{"openapi":"3.0.3","info":{"title":"","version":"1.0.0"},"paths":{},"components":{"schemas":{"Comp":{"type":"object"}},"securitySchemes":{"TLS":{"type":"mutualTLS"}}}}
It would be nice to have a single attribute for all fields of a struct deriving IntoParams
for style
.
Perhaps something like:
#[derive(Deserialize, IntoParams)]
#[param(style = Form)]
struct Filter {
/// Foo database id.
id: u64,
/// Datetime since foo is updated.
since: Option<String>,
}
Also what happens when different parameters in the same path have different parameter styles? Perhaps the style
attribute only makes sense on the container level?
I have the following handler:
#[utoipa::path(
context_path = "/api/v1/private/workers/{worker_id}/pipe_transports",
responses(
(status = 200, description = "Pipe Transport created"),
),
tag = "pipe_transports"
)]
#[post("")]
#[tracing::instrument(skip(state))]
pub async fn create(
req_path: Path<request::CreatePipeTransportRequestPath>,
state: Data<crate::state::AppStateHandle>,
) -> Result<Json<response::CreatePipeTransportResponse>, AppError> {
.......
}
with the following struct for the Path in a different file (request::CreatePipeTransportRequestPath
)
#[derive(Debug, Deserialize, Serialize, IntoParams)]
pub struct CreatePipeTransportRequestPath {
pub worker_id: WorkerId,
}
this result in the following error:
the trait bound
handlers::workers::pipe_transports::request::CreatePipeTransportRequestPath: utoipa::ParameterIn
is not satisfied
the traitutoipa::ParameterIn
is not implemented forhandlers::workers::pipe_transports::request::CreatePipeTransportRequestPath
but, if I put CreatePipeTransportRequestPath
in the same file as my create
handler, I don't have any error.
Tracking issue for deeper integration between axum and utoipa. Integration is similar to one existing for actix-web and rocket frameworks.
Tasks:
I have a struct like this:
#[derive(Debug, Serialize, Component)]
pub struct Foo<D, R> {
pub data: D,
pub resources: R,
}
And I want to use it like this with a rocket request handler:
#[utoipa::path(
get,
context_path = "/api/v1",
responses(
(status = 200, description = "Foo found", body = Foo<Bar, BarResources>),
(status = 404, description = "Foo was not found")
),
params(
("id" = Uuid, description = "Foo id"),
)
)]
#[get("/foo/<id>")]
I'm getting multiple errors:
Uuid
is not a Component
. I'm forced to write String
instead. I wish I could write Uuid
because it makes the doc clearer.<
, it expects a comma. So I guess the proc-macro can't handle generics yet, is this planned? :)I tried this instead:
pub type GetFooBody = Foo<Bar, BarResources>;
and then
(status = 200, description = "Foo found", body = GetFooBody),
then it compiles but I get an error in the browser when browsing the swagger doc:
Resolver error at paths./api/v1/foo/{id}.get.responses.200.content.application/json.schema.properties.data.$ref
Could not resolve reference: Could not resolve pointer: /components/schemas/D does not exist in document
Resolver error at paths./api/v1/foo/{id}.get.responses.200.content.application/json.schema.properties.resources.$ref
Could not resolve reference: Could not resolve pointer: /components/schemas/R does not exist in document
This refers to the type params D
and R
. Even though both Bar
and BarResources
are Component
, the proc-macro doesn't treat them as expected. And in the swagger UI, it shows both fields' type as string
:(
{
"data": "string",
"resources": "string"
}
Is it possible / planned to add support for generics? :)
So that I don't have to write a second set of types just for the doc, but can use the actual types that I'm using in the request handlers also for the doc.
In my API I would like a way to send any
data. Something like this
// Optional data, can be any JSON value
#[serde(skip_serializing_if = "Option::is_none")]
#[component(value_type = Any)]
data: Option<serde_json::Value>,
Unfortunately swagger-ui throws an error and it does not display it properly
I've noticed that the generated open API docs component fields don't seem to respect set serde rules -- namely rust conventions use snake_case
while JSON uses camelCase
.
Normally I've had to add a serde attribute (#[serde(rename_all = "camelCase")]
) to rename these when converting between the two. I have these added to my components currently but the generated code is still snake case.
Is there some option I can set so that the generated code will be in camel case format? Thanks!
#[derive(Component)]
struct Foo {
field: HashMap<String, u64>,
}
results in:
{
"properties": {
"field": {
"type": "object"
}
},
"required": [
"field"
],
"type": "object"
}
It looks like the spec https://swagger.io/specification/#schema-object should support the additionalProperties
type that can be used to provide a proper schema for the HashMap
?
{
"properties": {
"field": {
"type": "object",
"additionalProperties": {
"type": "integer",
"format": "uint64",
"minimum": 0
}
}
}
"required": [
"field"
],
"type": "object",
}
Tracking issue for improving actix-web integration. Goal for improvement is to enable path and query parameters to be resolved from structs.
Task to do:
#[derive(Component)]
struct Bar {
foo: (String, String)
}
or
#[derive(Component)]
struct Bar {
foo: (String)
}
I get the following error message:
unexpected type in component part get type path, expected one of: Path, Reference, Group
Hi, the following code causes a build error:
#[derive(Serialize, Component)]
struct Stats {
#[serde(serialize_with = "serialize_duration")]
pub uptime: Duration,
}
#[utoipa::path(
responses(
(status = 200, description = "Uptime", body = [Stats]),
),
)]
#[get("/stats")]
#[tracing::instrument(skip(state))]
async fn get_stats(state: web::Data<AppState>) -> web::Json<Stats> {
web::Json(Stats {
uptime: chrono::Local::now() - state.started_at,
})
}
This causes the error Expected doc attribute with one path segment
for the utoipa instrumentation. This is with actix-web:
actix-web = "4.0"
utoipa = { version = "0.1.2", features = [
"actix_extras",
"debug",
"chrono_types_with_format",
] }
The same error also happens with chrono_types
feature, or with the chrono feature disabled.
I need to override some types in my Path struct but it's not currently possible to do that*
#[derive(Debug, Deserialize, IntoParams)]
pub struct SomeStruct {
#[param(value_type = Uuid)]
pub some_id: SomeUUIDWrapper,
}
It would be great to be able to do the same thing as with Component
#[derive(Debug, Deserialize, Component)]
pub struct SomeStruct {
#[component(value_type = Uuid)]
pub some_id: SomeUUIDWrapper,
}
*for now I'll just remove the IntoParams
and define params
in path
and stay on 1.1.0 as it's not possible on master to have a Path<SomeStruct>
that doesn't implement IntoParams
Refactor Swagger UI configuration options to support variety of other options Swagger UI configuraiton has to offer.
Tasks to do:
If we design a struct with the special instruction flatten
of serde
it is not flatten during schema creation.
#[derive(Serialize, Deserialize, Debug, Clone, Component)]
pub struct SomePayload {
some_id: String,
#[serde(flatten)]
extras: ExtraContent,
}
So would it be possible to tackle that point, maybe like the example, format, write_only?
#[derive(Serialize, Deserialize, Debug, Clone, Component)]
pub struct SomePayload {
some_id: String,
#[serde(flatten)]
#[component(nested = true)]
extras: ExtraContent,
}
It would be nice to support tag = "..."
serde property for enums https://serde.rs/enum-representations.html#adjacently-tagged for the Component
derive macro.
Hello again,
I need to use some types that comes from a third party library but obviously they don't implement #[derive(Component)]
. I looked at the doc and tried to do something like this
#[derive(Debug, Deserialize, Component)]
pub struct SampleStruct {
...
#[component(value_type = Object)]
pub rtp_capabilities: RtpCapabilities,
...
}
but sadly it stills tries to create a ref to something that doesn't exist
"rtp_capabilities": {
"$ref": "#/components/schemas/RtpCapabilities"
},
what I would like instead is a way to specify that I want any kind of Object in #[component]
. Obviously it would be better to actually have the correct type, but this would at least create a correct OpenAPI file that I can use.
Or maybe I'm missing something?
For some reason it seems that if I use some generic in struct, at some point it does not infer the type and instead expect the generic letter as type.
NB: One thing so, it seems that I cannot declared a type using genercs over some utopia attribues like MyStruct<String>
(request_body, value_type etc), seems a parsing error - so I used alias, not a big deal as I already use a lot of them.
// This is dummy code, far form as complicated as in our code base but should provide enough insight I hope
type O1 = String;
type O2 = u64;
pub struct MyStruct<T> {
pub id: String,
pub content: OtherStruct<T>, // Please not that we could here use also another struct instead of simple alias over primitive types
}
type TopType1 = MyStruct<O1>;
#[openapi(
handlers(...),
components(TopType1, ...)
It returns something like this
"TopType1": {
"type": "object",
"required": [
"id", "content"
],
"properties": {
"id": {
"type": "string"
},
"content": {
"$ref": "#/components/schemas/T"
}
},
"description": "First round trip from requesting party to ask to build a receipt transaction"
}
I could obviously switch to use impl utoipa::Component for TopType1 {
and all other sub combination (on sub structs using aliases) but as it feels to me a bit overwhelming for an already big app I am wondering if I am missing something on configuration or any property or just not supported yet.
Any insight is welcome, thanks.
First of all thanks for the library, I like its simple syntax!
On rustc 1.60 I have no issues, but any version below (I tried 1.55 -> 1.59) doesn't seem to build on my computer or in our CI. This is a bit blocking for us, because we can't change the version of rustc in our CI right now.
Nevertheless, I think the MSRV should be displayed in the doc or the README if it is indeed 1.60.
I added some data examples on my manual schema (Uuid, type Alias etc) through the impl Modify
behavior, one of this example could be something like this
/// random values, could even be generated from proptest/quickcheck for struct
uuid_p.example = Some(serde_json::Value::String(Uuid::new_v4().to_string()));
Surprisingly I found that each time I requested the openapi.json
file, my examples are differents (this could come from the use of Modify
I did not dig that deeper).
IMHO this is not a big
issue but still it should not be the case.
Tracking issue for implementing general serve Swagger UI capability. Currently there is no easy way to use the utoipa-swagger-ui crate with other than actix-web framework. PR's added here will change that and plan is to provide easy to use interface for serving Swagger UI with other frameworks.
Also to demonstrate that there will be new example written with warp framework.
I have this type that occurs in a handler param:
#[derive(Debug, FromForm, Component)]
pub struct FilterParams {
pub ids: Option<VecParam<Uuid>>,
pub archived: Option<bool>,
#[form(field = "dueDateStart")]
pub due_date_start: Option<i64>,
#[form(field = "dueDateEnd")]
pub due_date_end: Option<i64>,
#[form(field = "periodStart")]
pub period_start: Option<String>,
#[form(field = "periodEnd")]
pub period_end: Option<String>,
}
params(
("filter_params" = FilterParams, description = "Filter parameters"),
)
)]
#[get("/results?<filter_params..>")]
I see that the field renaming attributes are ignored by the Component
derive macro. Could you modify it to take them into account? :)
Also, what's the best way to use this VecParam
generic type in a field, so that I don't have to duplicate the whole FilterParams
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.
This lib is awesome but I'm having a hard time getting the swagger-ui part to do what I need. Is there any configuration I can set so that the swagger-ui
endpoint displays my generated swagger doc vs displaying the petstore example? I've been able to see my generated swagger-ui by using the explore button and navigating to the path but I'd really like to serve my doc up by default and I'm not sure if I can do that with this lib. Thanks!
ETA: I have tried swagger-ui/api-doc/openapi.json
but that just gets me a 404
I have an existing warp
project that I want to add an OpenAPI spec to. But I had a problem: the handler functions for filters are in traits, so when I tried to use the utoipa::path
macro in front of the handler function, I got this compilation error:
error: struct is not supported in `trait`s or `impl`s
--> cloud_backend/src/crud.rs:465:5
|
465 | / #[utoipa::path(get,
466 | | path = "dataset/",
467 | | responses(
468 | | (status = 200, body = String)
469 | | )
470 | | )]
| |______^
|
= help: consider moving the struct out to a nearby module scope
= note: this error originates in the attribute macro `utoipa::path` (in Nightly builds, run with -Z macro-backtrace for more info)
error: implementation is not supported in `trait`s or `impl`s
--> cloud_backend/src/crud.rs:465:5
|
465 | / #[utoipa::path(get,
466 | | path = "dataset/",
467 | | responses(
468 | | (status = 200, body = String)
469 | | )
470 | | )]
| |______^
|
= help: consider moving the implementation out to a nearby module scope
= note: this error originates in the attribute macro `utoipa::path` (in Nightly builds, run with -Z macro-backtrace for more info)
My interpretation of this is that the utoipa::path()
macro writes a struct definition, which is then illegal because Rust does not allow those to be defined inside a trait.
Do I have any alternatives here? It would be difficult for me to rewrite the project to extract the handlers out of the trait. Would I have to write stub handlers that call the trait methods, solely for the purpose of being annotated by utoipa
?
My ideal option would be if I could annotate Filter objects, because that's the most basic part of my code.
Alternatively--can I write these structs myself? That may be less exciting but would make this work.
I apologize if I misunderstood something; I'm somewhat new to Rust and warp, and I just found out about utoipa today.
I'm dealing with an API that has a unique type for each response body, having them all as components is a bit of a headache, and they won't be re-used in other endpoints. It would be nice to have a way to optionally inline schema definitions. Perhaps with a special wrapper like inline()
, the path
macro could insert the schema for a derived Component
inline rather than attempting to reference it?
Route tags/namespaces at the moment are generated by what is provided in handlers
. Might there be a way to specify renames for these tags so that they can be more clear? For example
tags(
(paths = [route::admin::user], name = "Admin", description = "Admin endpoints."),
),
on openapi
for example?
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`
My utoipa doc tag is like
#[utoipa::path(
context_path = "/posts",
tag="Post",
request_body(content = CreatePostRequest, description = "New post data", content_type = "multipart/form-data"),
responses(
(status = 200, description = "create new post", body = String)
),
security(
("authorization"=[])
)
)]
and the content structure is
#[derive(Debug, Component)]
pub struct CreatePostRequest {
pub body: Option<String>,
pub tags: Option<Vec<u32>>,
#[component(format = ComponentFormat::Binary)]
pub audio_file: Option<File>,
}
How can I set audio_file
field as a file upload?
I have some actix web query structs that I cannot derive IntoParams because only primitive and String types are supported. Is there a way of skipping that and just providing the query params in the params(...) section in the #[path...] derive?
I'm not very fluent in the OpenAPI specifications, so I wanted to see if I was doing something wrong.
Using the example code, but saving the json to a file instead of using the swagger ui
When adding the OpenAPI json into insomnia it reports the error for each of the ErrorResponse examples:
oas3-valid-oas-content-example 'example' property should match exactly one schema in oneOf
For the OpenApi derive to work all the components must be in scope because you cannot use paths.
Taking from the Axum todo example, this is possible:
use crate::todo::{Store, Todo, TodoError};
#[derive(OpenApi)]
#[openapi(
handlers(
todo::list_todos,
todo::create_todo,
todo::mark_done,
todo::delete_todo,
),
components(Todo, TodoError),
modifiers(&SecurityAddon),
tags(
(name = "todo", description = "Todo items management API")
)
)]
struct ApiDoc;
this is not:
#[derive(OpenApi)]
#[openapi(
handlers(
todo::list_todos,
todo::create_todo,
todo::mark_done,
todo::delete_todo,
),
components(crate::todo::Todo, crate::todo::TodoError),
modifiers(&SecurityAddon),
tags(
(name = "todo", description = "Todo items management API")
)
)]
struct ApiDoc;
and if you have lots of components
this gets painful quickly. The handlers
section already supports this.
There is many way to declare route with actix::web
but for one of them is using scope (which is a must have imho, even better with macro route usage)
https://docs.rs/actix-web/3.3.3/actix_web/struct.Scope.html
/// main.rs
// app definition
...
.service(web::scope("/health").service(ping_pong))
/// health.rs
#[utoipa::path(
tag = "Health",
responses(
(status = 200
, description = "It should respond with \"pong\""
, body = String),
),
)]
#[get("/ping")]
pub async fn ping_pong() -> impl Responder {
HttpResponse::Ok().body("pong")
}
What will happen here is that if we do not explicitly declared the path (with full value) it will just be generate on openapi with /ping
instead of /health/ping
.
Example here is simple but in an application with a lot of subscope: version, resources, action, sub resources it becomes more and more tricky to be sure to keep everything aligned (people will obviously drop declaring partial scope in favor or routes hidden in some other files),
Would it be possible to support scope?
Running cargo check --all-features
on master currently produces the following errors:
error[E0119]: conflicting implementations of trait `ext::ArgumentResolver` for type `ext::PathOperations`
--> utoipa-gen/src/ext/rocket.rs:23:1
|
23 | impl ArgumentResolver for PathOperations {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `ext::PathOperations`
|
::: utoipa-gen/src/ext/actix.rs:31:1
|
31 | impl ArgumentResolver for PathOperations {
| ---------------------------------------- first implementation here
error[E0119]: conflicting implementations of trait `ext::PathOperationResolver` for type `ext::PathOperations`
--> utoipa-gen/src/ext/rocket.rs:186:1
|
186 | impl PathOperationResolver for PathOperations {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `ext::PathOperations`
|
::: utoipa-gen/src/ext/actix.rs:174:1
|
174 | impl PathOperationResolver for PathOperations {
| --------------------------------------------- first implementation here
error[E0119]: conflicting implementations of trait `ext::PathResolver` for type `ext::PathOperations`
--> utoipa-gen/src/ext/rocket.rs:259:1
|
259 | impl PathResolver for PathOperations {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `ext::PathOperations`
|
::: utoipa-gen/src/ext/actix.rs:217:1
|
217 | impl PathResolver for PathOperations {
| ------------------------------------ first implementation here
error[E0592]: duplicate definitions with name `get_type_path`
--> utoipa-gen/src/ext/actix.rs:108:5
|
108 | fn get_type_path(ty: &Type) -> &TypePath {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `get_type_path`
|
::: utoipa-gen/src/ext/rocket.rs:159:5
|
159 | fn get_type_path(ty: &Type) -> &TypePath {
| ---------------------------------------- other definition for `get_type_path`
error[E0592]: duplicate definitions with name `get_fn_args`
--> utoipa-gen/src/ext/actix.rs:141:5
|
141 | fn get_fn_args(fn_args: &Punctuated<FnArg, Comma>) -> impl Iterator<Item = Arg> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `get_fn_args`
|
::: utoipa-gen/src/ext/rocket.rs:89:5
|
89 | fn get_fn_args(fn_args: &Punctuated<FnArg, Comma>) -> impl Iterator<Item = Arg> + '_ {
| ------------------------------------------------------------------------------------ other definition for `get_fn_args`
In the sample petstore swagger1, there is a description for each supported API method. For example, Add a new pet to the store
2.
So far I found no way to add such a method description in utoipa. I tried different ways to add a description or summary to the handler definition, or to the #[utoipa::path(...)]
annotations, but couldn't get it to work. Looks like its currently not supported.
Can you please add support for that? Would be very useful.
Thanks.
I am trying to use utoipa-swagger-ui with oauth2 (https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/oauth2.md). I need to be able to set the usePkceWithAuthorizationCodeGrant
flag so that I can authorize with pkce. Is there currently a way to support this or something that could be added?
Tracking issue for improving OpenAPI parameter configuration options. Currently configuration options are limited to pretty much defaults. Actions taken within this issue will address this fact and provide feasible configuration options for the parameters.
Action points
param
arguments to configure parameter#[utoipa::path(...)]
params()
section to allow more configuration options for parametersA declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.