netwo-io / apistos Goto Github PK
View Code? Open in Web Editor NEWActix-web wrapper for automatic OpenAPI 3.0 documentation generation.
License: MIT License
Actix-web wrapper for automatic OpenAPI 3.0 documentation generation.
License: MIT License
Currently if I want to use the api_operation macro the following way, there is no problem:
#[api_operation(summary = "Get an element from the todo list")]
pub(crate) async fn get_todo(todo_id: Path<Uuid>) -> Result<Json<Todo>, Error> {
// because it is a sample app, we do not currently implement any logic to store todos
Ok(Json(Todo {
id: todo_id.into_inner(),
title: "some title".to_string(),
description: None,
}))
}
But if I want to use it like that:
#[api_operation(summary = "Get an element from the todo list")]
pub(crate) async fn get_todo() -> Result<Json<Todo>, Error> {
// because it is a sample app, we do not currently implement any logic to store todos
Ok(Json(Todo {
id: Uuid::new_v4(),
title: "some title".to_string(),
description: None,
}))
}
I get a compilation error:
error[E0282]: type annotations needed
--> src/api.rs:22:1
|
22 | #[api_operation(summary = "Get an element from the todo list")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
= note: this error originates in the macro `vec` which comes from the expansion of the attribute macro `api_operation` (in Nightly builds, run with -Z macro-backtrace for more info)
Just to keep track of the fact that we should definitely use the original schemars in our dependencies as soon as GREsau/schemars#264 is merged
Hello,
Thank for fixing most of the errors, but there is some left.
error[E0599]: no function or associated item named responses
found for struct ResponseWrapper
in the current scope
error[E0599]: no function or associated item named schema
found for struct ResponseWrapper
in the current scope
error[E0599]: no function or associated item named child_schemas
found for struct ResponseWrapper
in the current scope
error[E0599]: no function or associated item named error_schemas
found for struct ResponseWrapper
in the current scope
Error is like:
function or associated item not found in ResponseWrapper<Box<dyn futures_util::Future<Output = actix_web::Either<Result<HttpResponse, actix_web::Error>, HttpResponse>> + Unpin>, __openapi_accept_presentation>
Hello,
I don't know if it's an Apistos issue or swagger, but when using path containing regex like this one:
scope("/imgsrv").service(resource("{path:.+}/tile").route(get().to(endpoints::tile::<T>)))
It generate this swagger:
As you can see the curl request is wrong, the {path:.+}
is not replaced by test.tif
.
It works well if I use the syntax {path}
.
One way to fix it may be to sanitize before generating the openapi.json WDYT ?
Thank you
Hello,
I am trying to use apistos and actix-identity at the same time.
When I use
#[api_operation(tag = "another", summary = "Operator index endpoint")]
pub async fn test(user: Identity) -> HttpResponse {
It gives me error.
"no function or associated item named request_body
found for struct actix_identity::Identity
in the current scope".
For successfully compile the code I have to add skip=true. But now my function is not documented at openapi. Please add ability to ignore variable name or structs. Ignoring Identity struct will solve my problem.
I made a running example reproducing one of the API endpoints of my applications that generates a strange openapi.json. Code below.
The problem is firstly that it generates the wrong URI path: /api/v1/admin/admin
. Expected would be /api/v1/admin/measurement/{measurement_id}
. Secondly, the swagger editor complains:
Semantic error at paths./api/v1/admin/admin.delete.parameters.0.name
Path parameter "" must have the corresponding {} segment in the "/api/v1/admin/admin" path
Jump to line 16
main.rs
use actix_web::middleware::Logger;
use actix_web::web::{Json, Path};
use actix_web::Error as ActixError;
use actix_web::{App, HttpServer};
use apistos::app::OpenApiWrapper;
use apistos::info::Info;
use apistos::server::Server;
use apistos::spec::Spec;
use apistos::web::{delete, scope};
use apistos::{api_operation, ApiComponent};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::net::Ipv4Addr;
use uuid::Uuid;
#[derive(Serialize, Deserialize, Debug, Clone, ApiComponent, JsonSchema)]
pub struct DeleteMeasurementInput {
pub disk: Option<MoveMeasurement>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, ApiComponent, JsonSchema)]
pub enum MoveMeasurement {
/// Move to create/ folder
ToCreate,
/// Move to _DELETE/ folder
Delete,
}
#[derive(Serialize, Deserialize, Debug, Clone, ApiComponent, JsonSchema)]
pub struct DeleteMeasurementOutput {
pub delete_job_id: Result<Uuid, String>,
/// Whether the measurement was moved on disk, with eventual error.
/// Ok(None) means no action was done
pub disk_result: Result<Option<MoveMeasurement>, String>,
}
#[api_operation(summary = "Get an element from the todo list")]
pub async fn admin_delete_measurement(
_path: Path<i64>,
_body: Json<DeleteMeasurementInput>,
) -> Result<Json<DeleteMeasurementOutput>, ActixError> {
unimplemented!()
}
#[actix_web::main]
async fn main() -> Result<(), impl Error> {
HttpServer::new(move || {
let spec = Spec {
info: Info {
title: "A well documented API".to_string(),
description: Some(
"This is an API documented using Apistos,\na wonderful new tool to document your actix API !".to_string(),
),
..Default::default()
},
servers: vec![Server {
url: "/api/v3".to_string(),
..Default::default()
}],
..Default::default()
};
App::new()
.document(spec)
.wrap(Logger::default())
.service(
scope("/api/v1")
.service(scope("/admin").route(
"/measurements/{measurement_id}",
delete().to(admin_delete_measurement),
)),
)
.build("/openapi.json")
})
.bind((Ipv4Addr::UNSPECIFIED, 8080))?
.run()
.await
}
Cargo.toml
[package]
name = "t"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.8.0"
apistos = { version = "0.1", features = ["extras", "qs_query"] }
schemars = { package = "apistos-schemars", version = "0.8", features = ["chrono", "uuid1", "url", "rust_decimal"] }
serde = "1.0.204"
uuid = "1.10.0"
The generated openapi.json
:
{"openapi":"3.0.3","info":{"title":"A well documented API","description":"This is an API documented using Apistos,\na wonderful new tool to document your actix API !","version":""},"servers":[{"url":"/api/v3"}],"paths":{"/api/v1/admin/admin":{"delete":{"summary":"Get an element from the todo list","operationId":"delete_api-v1-admin-admin-f8aeb0610e9d768f59fdb7944e4f9ae1","parameters":[{"name":"","in":"path","required":true,"schema":{"title":"int64","type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteMeasurementInput"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteMeasurementOutput"}}}}},"deprecated":false}}},"components":{"schemas":{"DeleteMeasurementInput":{"title":"DeleteMeasurementInput","type":"object","properties":{"disk":{"allOf":[{"$ref":"#/components/schemas/MoveMeasurement"}],"nullable":true}}},"DeleteMeasurementOutput":{"title":"DeleteMeasurementOutput","type":"object","required":["delete_job_id","disk_result"],"properties":{"delete_job_id":{"$ref":"#/components/schemas/Result_of_Uuid_or_String"},"disk_result":{"description":"Whether the measurement was moved on disk, with eventual error. Ok(None) means no action was done","allOf":[{"$ref":"#/components/schemas/Result_of_Nullable_MoveMeasurement_or_String"}]}}},"MoveMeasurement":{"oneOf":[{"title":"ToCreate","description":"Move to create/ folder","type":"string","enum":["ToCreate"]},{"title":"Delete","description":"Move to _DELETE/ folder","type":"string","enum":["Delete"]}]},"Result_of_Nullable_MoveMeasurement_or_String":{"oneOf":[{"title":"Ok","type":"object","required":["Ok"],"properties":{"Ok":{"allOf":[{"$ref":"#/components/schemas/MoveMeasurement"}],"nullable":true}}},{"title":"Err","type":"object","required":["Err"],"properties":{"Err":{"type":"string"}}}]},"Result_of_Uuid_or_String":{"oneOf":[{"title":"Ok","type":"object","required":["Ok"],"properties":{"Ok":{"type":"string","format":"uuid"}}},{"title":"Err","type":"object","required":["Err"],"properties":{"Err":{"type":"string"}}}]}}}}
Try it at https://editor.swagger.io/
I'm using apistos with actix-web.
Part of my service settings are using configure()
.service(
web::scope("/admin")
.app_data(admin_data.clone()) // admin state // maybe divide it into each configuration level
.configure(routes::api_admin_login_config)
.configure(routes::api_admin_users_config)
.configure(routes::api_admin_users_id_config),
)
Part of configuration is
pub fn api_admin_users_id_config(cfg: &mut web::ServiceConfig) {
cfg.service(
web::resource("/users/{user_id}")
.route(web::get().to(handlers::admin::get_user))
.route(web::put().to(handlers::admin::update_user))
.route(web::delete().to(handlers::admin::delete_user))
.wrap(from_fn(auth_jwt::mw_admin_auth_jwt)),
);
}
However, .wrap(from_fn(auth_jwt::mw_admin_auth_jwt))
can't work here though it works using actix_web::web.
Error message says,
the trait bound `apistos::web::Resource<actix_web::Resource<impl ServiceFactory<ServiceRequest, Config = (), Response = ServiceResponse<impl MessageBody>, Error = actix_web::Error, InitError = ()>>>: apistos::internal::definition_holder::DefinitionHolder` is not satisfied
the trait `apistos::internal::definition_holder::DefinitionHolder` is implemented for `apistos::web::Resource`
I need to set warp() with middleware at each resource but I don't know how.
Hello
I'm facing an issue with the macro api_operation.
here is my code :
pub(crate) fn config<T: AnalysisInterface + 'static>() -> Scope {
scope("/analyze")
.service(_config::<T, Product1<SubProductA>>())
.service(_config::<T, Product1<SubProductB>>())
.service(_config::<T, Product2<SubProductA>>())
.service(_config::<T, Product2<SubProductB>>())
}
fn _config<T: AnalysisInterface + 'static, R: Product + Send + 'static>() -> Resource {
let route =
"/{product_id}/{algo_version}".replace("{product_id}", &T::product_name::<R>());
resource(&route).route(post().to(start_analysis::<T, R>))
}
#[api_operation(summary = "Start an analysis")]
#[instrument(skip(data))]
async fn start_analysis<T: AnalysisInterface, R: Product + Send + 'static>(
data: Data<T>,
_: Path<String>,
Json(req): Json<AnalyzeRequest>,
) -> Result<AnalyzeResponse, AppError> {
let res = data.start_analyze::<R>(req).await?;
Ok(res)
}
I know this is kind of tricky to have a generic handler and register it multiple times.
But do you think it should works or it's better to create multiple handler, one for each case (4 here in this example).
The error message:
error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
--> src/server/v0/analysis.rs:40:1
|
40 | #[api_operation(summary = "Get status of the service")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
41 | #[instrument(skip(data))]
42 | async fn start_analysis<T: AnalysisInterface, R: Product + Send + 'static>(
| - help: remove this generic argument
Thank you for your help
We should check what would be needed to support OAS 3.1 instead of 3.0 and possibly plan that.
First of all thank you for quick fix about last feature request. It solved my biggest issues. This issue is not critical but would-be-nice type of issue. Error is:
When I wrote like that api operation throws bunch of errors.
#[actix_web_grants::protect("ADMIN")]
#[api_operation(
tag = "test",
summary = "test endpoint",
skip_args = "identity"
)]
pub async fn test_fun(
Errors:
error[E0599]: no function or associated item named `parameters` found for struct `AuthDetails` in the current scope
function or associated item not found in `ResponseWrapper<Box<dyn Future<Output = Either<Result<HttpResponse, Error>, HttpResponse>> + Unpin>, ...>`
error[E0599]: no function or associated item named `required` found for struct `AuthDetails` in the current scope
I am using sea orm cli to generate data entities.
They seem to have the same name(Model) in the generated OpenAPI.
I have been looking for a way to solve the problem of duplicate structure names.
Currently, I have found that I can use
# [serve (rename="seedQueryDto")]
However, it is not convenient to use sea orm cli to generate entities.
Do you have a good solution to solve the problem of duplicate structure names?
In the provided code snippet, there appears to be a typo in the usage of the type ResponseWrapper. It seems that ResponseWrapper should actually be ResponderWrapper according to the context.
Here's the corrected snippet:
if string_type == "impl Responder" {
is_responder = true;
*_type = Box::new(
match syn::parse2(quote!(
impl std::future::Future<Output=apistos::actix::ResponderWrapper<#_type>>
)) {
Ok(parsed) => parsed,
Err(e) => abort!("parsing impl trait: {:?}", e),
},
);
}
https://github.com/netwo-io/apistos/blob/main/apistos-gen/src/internal/mod.rs#L153
I'm just starting to wrap my API in this library. I got this error
error[E0599]: no function or associated item named `from_iter` found for struct `BTreeMap` in the current scope
--> orchestrator/src/endpoints/measurements.rs:74:1
|
74 | #[api_operation(summary = "Get an element from the todo list")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item not found in `BTreeMap<_, _, _>`
|
note: if you're trying to build a new `BTreeMap<_, _, _>` consider using one of the following associated functions:
BTreeMap::<K, V>::new
BTreeMap::<K, V, A>::new_in
BTreeMap::<K, V, A>::bulk_build_from_sorted_iter
--> /home/ploppz/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/collections/btree/map.rs:629:5
|
629 | pub const fn new() -> BTreeMap<K, V> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
674 | pub const fn new_in(alloc: A) -> BTreeMap<K, V, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
1472 | / pub(crate) fn bulk_build_from_sorted_iter<I>(iter: I, alloc: A) -> Self
1473 | | where
1474 | | K: Ord,
1475 | | I: IntoIterator<Item = (K, V)>,
| |_______________________________________^
= help: items from traits can only be used if the trait is in scope
= note: this error originates in the attribute macro `api_operation` (in Nightly builds, run with -Z macro-backtrace for more info)
help: trait `FromIterator` which provides `from_iter` is implemented but not in scope; perhaps you want to import it
|
1 + use std::iter::FromIterator;
|
Just want to suggest to use fully qualified syntax to use FromIterator::from_iter
for example so that library users don't have to import that trait.
At the moment, it seems that only error responses can be documented using #[openapi_error(...)]
. It would be useful to also be able to provide a description for successful responses. Moreover, an API might return different successful responses, i.e. 200 and 201 might both be valid. Are there any plans to add this in the future?
Hi.
Is it possible to use utoipa_swagger_ui (actix-web feature) with apistos, or do you have plan to implement a new one?
I tried something like this with no success:
let swagger = SwaggerUi::new("/{_:.*}").url("/openapi.json", ApiDoc::openapi()); App::new() .service(scope("/docs") .service(resource("").to(swagger)) ) .build("/openapi.json")
Would you like to share a suggestion?
I define the route in the following way.
web::scope("/ticket").service(resource("/").route(put().to(update_ticket)))
apistos: /ticket
actix-web: /ticket/
Hello,
Thank you for you work.
Would it be possible to add under a feature flag support for camino::Utf8Path ?
I can create the PR if you want.
Hello,
I would like to generate an openapi def for this struct:
#[derive(Debug, MultipartForm, ApiType)]
pub struct UploadForm {
pub main: TempFile,
pub dependencies: Vec<TempFile>,
}
impl TypedSchema for UploadForm {
fn schema_type() -> InstanceType {
InstanceType::Object
}
fn format() -> Option<String> {
None
}
}
Unfortunately I'm stuck on how to do that, obviously I cannot use JsonSchema since it doesn't work with TempFile.
Any help would be really appreciated.
Thank you
Runing the example petstore project, there are no openapi.json
PS C:\Users\User\documents\projects\apistos\examples\petstore> cargo run
info: syncing channel updates for '1.74.0-x86_64-pc-windows-msvc'
info: latest update on 2023-11-16, rust version 1.74.0 (79e9716c9 2023-11-13)```
Hi,
I would like to use this crate in a shuttle.rs environment.
As you can see on the following link, in a shuttle based actix-web application you dont have access to the actix web app sturct directly.
Is there anyway to use this crate through service configuration?
A 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.