Giter VIP home page Giter VIP logo

apistos's People

Contributors

axelfaure avatar boehm-s avatar ferid-akifzade avatar gschulze avatar jayvdb avatar oss-netwo avatar rlebran avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

apistos's Issues

Add support for function without any argument for the api_operation macro

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)

Still have errors with actix-web-grants

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>

Paths with regex

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:

image

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

Ability to exclude some structs

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.

Generates wrong path

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/

Can't use wrap() function in resource

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.

Api operation on generic handler

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

New update is not compatible with macro mode of actix_web_grants

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

Duplicate name(sea-orm-cli)

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?

Incorrect Usage of ResponseWrapper Instead of ResponderWrapper

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 have to `use std::iter::FromIterator;` in code calling the api_operation macro

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.

Possibility to document successful responses.

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?

Swagger UI for apistos like utoipa_swagger_ui

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")
image

Would you like to share a suggestion?

OpenApi with multipart & TempFile

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

No generated file on Windows

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)```

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.