Git Product home page Git Product logo

okapi's People

Contributors

bouncyllama avatar dob9601 avatar gresau avatar itzbobocz avatar mateuszkj avatar matt-phylum avatar mautamu avatar maximeborges avatar mentaljam avatar mikeplus64 avatar mpajkowski avatar mtumilowicz avatar nomick avatar olback avatar petergarnaes avatar raffomania avatar ralpha avatar somehowchris avatar thoucheese avatar timando avatar totalkrill avatar west14 avatar zbentley avatar zlnpgtdtfezf 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  avatar  avatar  avatar

okapi's Issues

Okapi obfuscates compiler errors

Thank you for this project! I've been struggling with documenting an API I build, and keeping that documentation up to date. I'm trying to add okapi to my project to have the documentation be created automatically. Unfortunately, I'm running into some issues:

As it stands, Rocket is able to provide neat Rust error messages. Consider the following example:

#![feature(decl_macro, proc_macro_hygiene)]

use rocket::{get, routes};
use rocket_contrib::json::Json;

#[derive(serde::Serialize)]
struct Response {
    reply: String,
}

#[get("/")]
fn my_controller() -> Json<Response> {
    Json(Response {
        reply: 0,
    })
}


fn main() {
    rocket::ignite()
        .mount("/", routes![my_controller])
        .launch();
}

This fails with a compile error:

[me@mycomputer tmp]$ cargo check
    Checking tmp v0.1.0 (/home/me/code/rust/tmp)
error[E0308]: mismatched types
  --> src/main.rs:17:16
   |
17 |         reply: 0,
   |                ^
   |                |
   |                expected struct `std::string::String`, found integer
   |                help: try using a conversion method: `0.to_string()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `tmp`.

However, when the code is changed to use Okapi:

#![feature(decl_macro, proc_macro_hygiene)]

use rocket::get;
use rocket_contrib::json::Json;
use rocket_okapi::{openapi, routes_with_openapi};
use schemars::JsonSchema;

#[derive(serde::Serialize, JsonSchema)]
struct Response {
    reply: String,
}

#[openapi]
#[get("/")]
fn my_controller() -> Json<Response> {
    Json(Response {
        reply: 0,
    })
}


fn main() {
    rocket::ignite()
        .mount("/", routes_with_openapi![my_controller])
        .launch();
}

The error message changes:

[me@mycomputer tmp]$ cargo check
    Checking tmp v0.1.0 (/home/me/code/rust/tmp)
error[E0308]: mismatched types

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
error: could not compile `tmp`.

The useful information about what caused the compilation error is gone, making it really hard to debug. Is there any way to get it back?

okapi_add_operation_for_ visible in my projects documentation

When i generate rustdoc for my project, I find okapi_add_operation_for_ functions in the documentation, which is a bit confusing since these are not visible in the project source anywhere (since I assume they are derived from the okapi macros).
I assume it would be good if these functions could be generated with #[doc(hidden)] somehow...

Warning for feature(specialization)

With the new nightly compiler I get the following warning.

warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
 --> rocket_okapi/src/lib.rs:1:12
  |
1 | #![feature(specialization)]
  |            ^^^^^^^^^^^^^^
  |
  = note: `#[warn(incomplete_features)]` on by default
  = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information

Referring to this line:

#![feature(specialization)]

I have not looked into this much and everything seems to work fine, but just so you know.

how do I set a default value for a parameter?

I am quite new to rust and found that default parameter is not allowed in rust.

but I could not find a way to set a default value for a parameter in the swagger documentation page.

How can I set the default value for like page = 1 in such codes?

#[openapi(tag = "Customer")]
#[get("/customer?<limit>&<page>")]
pub async fn get_customers(
    db: &State<Database>,
    limit: i64,
    page: Option<i64>,
) -> Result<Json<Vec<Customer>>, Json<MessageResponse>> 

Missing instances OpenApiFromRequest

Hi, I'm trying to set up rocket_okapi in my project and getting some errors:

// I can't find this instance (rocket_db_pools::Connection<T>)
the trait `OpenApiFromRequest<'_>` is not implemented for `rocket_db_pools::Connection<db::MyDB>`

// There is an instance for &State<T> but T has to have 'static lifetime... I'm not sure how that is possible?
the trait `OpenApiFromRequest<'_>` is not implemented for `&rocket::State<MyState>`

// I can find this instance* but I'm not sure why I'm getting this for MyType, since it derives Deserialize and JsonSchema
// * https://docs.rs/rocket_okapi/0.8.0-rc.1/rocket_okapi/request/trait.OpenApiFromData.html
the trait `OpenApiFromData<'_>` is not implemented for `rocket::serde::json::Json<MyType>`

And this one which is not a missing instance, I think it has to do with using #[macro_use] extern crate rocket;:

expected enum `rocket_http::method::Method`, found enum `rocket::http::Method`
note: perhaps two different versions of crate `rocket_http` are being used?

Package versions:

schemars = "0.8"                                                 
okapi = { version = "0.7.0-rc.1" }                               
rocket_okapi = { version = "0.8.0-rc.1", features = ["swagger"] }
                                                                 
[dependencies.rocket]                                            
git = "https://github.com/SergioBenitez/Rocket"                  
version = "0.5.0-rc.1"                                           
features = ["json"]                                              
                                                                 
[dependencies.rocket_db_pools]                                   
git = "https://github.com/SergioBenitez/Rocket"                  
version = "0.1.0-rc"                                             
features = ["sqlx_postgres"]                                     

Thanks...

#[openapi] macro generates invalid code with mutable route param

I have modified the included example to a version that does not compile:

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_okapi;

use rocket_contrib::json::Json;
use rocket_okapi::swagger_ui::*;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
struct User {
    user_id: u64,
    username: String,
    #[serde(default)]
    email: Option<String>,
}

#[openapi]
#[get("/user/<id>")]
fn get_user(mut id: u64) -> Option<Json<User>> {
    Some(Json(User {
        user_id: id,
        username: "bob".to_owned(),
        email: None,
    }))
}

#[openapi]
#[post("/user", data = "<user>")]
fn create_user(mut user: Json<User>) -> Json<User> {
    user
}

fn main() {
    rocket::ignite()
        .mount(
            "/",
            routes_with_openapi![get_user, create_user],
        )
        .mount(
            "/swagger-ui/",
            make_swagger_ui(&SwaggerUIConfig {
                url: Some("../openapi.json".to_owned()),
                urls: None,
            }),
        )
        .launch();
}

This creates a problem here and here.

The problem is that the generated key generated here will include the mut (for example mut id instead of id). The macro assumes the rocket parameter names matches the generated keys exactly, but as explained, the keys might contain mut.

This gives a very confusing error message:

error: macros that expand to items must be delimited with braces or followed by a semicolon
  --> examples/json-web-api/src/main.rs:32:1
   |
32 | #[openapi]
   | ^^^^^^^^^^
help: change the delimiters to curly braces
   |
32 |  {[openapi}
   |  ^        ^
help: add a semicolon
   |
32 | #[openapi];
   |           ^
error: Could not find argument id matching path param.
  --> examples/json-web-api/src/main.rs:32:1
   |
32 | #[openapi]
   | ^^^^^^^^^^
error[E0425]: cannot find function `okapi_add_operation_for_get_user_` in this scope
  --> examples/json-web-api/src/main.rs:58:49
   |
58 |             routes_with_openapi![get_user, create_user],
   |                                                 ^^^^^^^^ help: a function with a similar name exists: `okapi_add_operation_for_create_user_`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0425`.
error: Could not compile `json_web_api`.
To learn more, run the command again with --verbose.

rocket::http::Status as oapi responder

It seems that rocket::http::Status does not implement OpenApiResponder, so that simple route will fail:

use rocket::http::Status;

#[get("/")]
fn func() -> Status { Status::Ok }

It's quite tricky, because the interface is not supposed to have access to the object itself, only type. As a temporary workaround l4l@9206ab2 may work, though I don't really think it's a good idea to merge it.

Maybe some wrapper should be considered for statuses? Procedural macros cannot properly determine whether the item is particular type or not in general, afaik, although they may emit warnings for a wrapper hinting.

Rocket Json does not implement JsonSchema for rocket special types error

Hey :)

Due to some post on a ticket (which I currently do not find) I tried to implement this on one of my projects (which contains one of the special types things for rocket).

Now I have the following endpoint

#[openapi(tag="Orders")]
#[post("/", data = "<data>", format = "application/json")]
pub async fn create_order(
    db_state: &State<MongoState>,
    data: Json<CreateOrderRequest>,
) -> Result<Json<OrderResponse>, (Status, Json<ErrorMessage>)> {
    // some things happen...
}

For that I get the following error:

the trait bound `rocket::serde::json::Json<rust_common::models::rocket::ErrorMessage>: schemars::JsonSchema` is not satisfied

Well ErrorMessage Isn't a huge thing

#[derive(Serialize, Deserialize, std::fmt::Debug, JsonSchema)]
pub struct ErrorMessage {
    pub message: String,
    pub code: u16,
}

Am I doing something wrong? Other endpoints with the option of json do work

Support for request guards

Hey!
First of all: Amazing crate! Thank you very much for this!

I am using request guards to add authentication to my application. This requires the user to add the Authorization header to a number of requests.

I would like to specify this in the API documentation.

An example function can look like this:

#[openapi]
#[get("/get")]
pub fn get_account_information(me: State<Account>, auth: Authenticate) -> Result<Json<AccountInformation>, Failure>
{
  me.get(auth.0)
    .and_then(|acc_info| Ok(Json(acc_info)))
}

The authentication guard returns 401 if the token does not match any user and adds the header requirement to the request.

Add 'discriminator' property on anyOf relations for use with openapi-generate

With the default settings, unions are rendered using the 'anyOf' relation, which is fine:

TreeModel:
      anyOf:
        - $ref: '#/components/schemas/ScoreTree'
        - $ref: '#/components/schemas/SongTree'
        - $ref: '#/components/schemas/PartTree'
        - ... etc

But when you want to use the OpenAPI generator to generate client code, the enum declaration needs (at least >= openapi-generator v5.0.0) a 'discriminator' property: https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/

This seems to correlate with serde's #[serde(tag = "type")] serialization option for enums.

Edit: seems to be more related to Schemars. Pre-existing issue: GREsau/schemars#39

[Rocket] Typehint `String` on `application/octet-stream`

Hi :)

First of all, thanks for creating and maintaining okapi. It's super helpful!

I stumbled upon a little issue when designing routes for file upload.
In our design, files could be uploaded in raw form as an application/octet-stream to our route.
As far as I understand, the expected way of doing this in rocket is to use the Data helper.

However in your code-base, there's currently String set as the type for the stream. One would expecte [u8] for an octet stream.

#[openapi(tag = "files")]
#[post("/<entity_id>", data = "<data>")]
pub async fn create_file(
    entity_id: Uuid,
    data: Data<'_>,
    ...

The generated spec:

        "requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string"
              }
            }
          },
          "required": true
        },

The expected spec:

        "requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "integer",
                  "format": "uint8",
                  "minimum": 0.0
                }
              }
            }
          },
          "required": true
        },

This popped up as an issue, when we tried to upload files via our frontend, but the typechecks failed as the schema expected a String.
Using &[u8] instead of Data works fine and crates the correct schema, however that's not how one works with files in Rocket and brings its own ploblems with Rocket's default data limits.

I'm not 100% sure if this is indeed a bug, of if we're just abusing the spec.

Adding tags to resources

I couldn't see if this was supported in the docs, but what I'd like to do it add tags to resources to group them together, as demonstrated on https://swagger.io/docs/specification/grouping-operations-with-tags/.

One possible way to support this would be to add an attribute to openapi:

#[openapi(tag="example")]
#[get("/")]
fn example() -> status::NoContent
    unimplemented!()
}

From there, you could have a trait along the lines of the following:

pub trait OpenApiTag {
    fn tag(gen: &mut OpenApiGenerator) -> OpenApiTag;
}

Plus some code to stitch it together as I can't currently see a way for the generator to add tags.

Stucturing large projects

Hi @GREsau,

I'm using okapi in a large project (~200 endpoints), and all of these endpoints need to be documented. Currently, I have separated these endpoints into modules, that each publicly export a function called get_routes. This function internally uses the routes_with_openapi macro to generate a Vec<rocket::Route>, and then the Rocket instance mounts the results of these functions on a separate mount point. The issue with this approach is that this will generate many openapi.json files instead of one. This in turn does not play well with swagger-codegen to automatically generate client libraries, and it is unfamiliar for many front enders. In the ideal case, I think we should generate one openapi.json file containing information about all documented routes in the Rocket instance.

I talked to @ralpha about this, and we both tried to cobble together something basic, but both our approaches hit a dead end. My approach was to create two macros called merge_routes and mount_routes, which supersedes the mounting functionality in Rocket. mount_routes would handle the namespacing that is normally handled by Rocket, and the merge routes would merge together the openapi.json's that have been created for each group of routes. I had imagined to build something along these lines:

let routes = merge_routes![
    mount_routes!["/module1", routes_with_openapi![route1, route2]],
    mount_routes!["/module2", routes_with_openapi![route3, route4]],
];
rocket::ignite().mount("/", routes).launch();

I seems a little silly to me however, to redo the work that Rocket is already doing, and to merge the json files instead of maybe generating one already correct file. I was wondering I you had run into this problem yet, and if so, if you had any thoughts on how to solve it?

Unable to deserialize SecurityScheme

I've run into an issue beyond my Rust knowledge when trying to deserialize a SecurityScheme. This test will repro.

#[test]
fn test_deser_security_scheme() -> Result<(), Box<dyn std::error::Error>> {
    let raw = r#"{
        "type": "apiKey",
        "description": "AWS Signature Version 4 authentication",
        "name": "Authorization",
        "in": "header",
        "x-amazon-apigateway-authtype": "awsSigv4" 
    }"#;

    let deser: openapi3::SecurityScheme = serde_json::from_str(raw)?;

    assert_eq!(
        deser,
        openapi3::SecurityScheme {
            schema_type: "apiKey".to_string(),
            description: Some("AWS Signature Version 4 authentication".to_string()),
            data: openapi3::SecuritySchemeData::ApiKey {
                location: "header".to_string(),
                name: "Authorization".to_string(),
            },
            extensions: okapi::Map::new() // should have x-amazon-apigateway-authtype
        }
    );
    Ok(())
}

Deserializing fails with Error: Error("missing field type", line: 7, column: 5). type is definitely there though. It has to have something to with https://github.com/GREsau/okapi/pull/56/files#diff-fb72987bae6646074514b23cd41d13a4d1b851455b9bf21084a32668fd729196 but I'm not sure what.

Route `format` mime type should be used

Currently the format tag is ignored in routes.

#[openapi]
#[post("/create", data = "<data>", format = "text/plain")]
fn something(...) -> ...{
}

Screenshot from 2021-10-12 19-16-29
This should not be ignored but used.

This issue is also related to #10

Not creating response schema, when content type is application/octet-stream

When the content type is application/octet-stream, no schema is created for the response, but it is created for the request. In this case, if there is no schema, openapi-generator typescript-fetch throws an error after version 5.3.1.
like this: Undefined property/schema for 'SchemaFor200ResponseBodyApplicationOctetStream'

for request it creates :

"requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "integer",
                  "format": "uint8",
                }
              }
            }
          } 

But for response it creates any schema:

"responses": {
          "200": {
            "content": {
              "application/octet-stream": {}
            }
          },

Trying to use a form with a rocket::fs::Tempfile with okapi

Hi,

I'm trying to use okapi to generate openapi.yaml, but I'm having problems because the datatypes that I'm trying to use perhaps aren't supported by okapi, or perhaps that I don't understand the way they are supported. I have ended up implementing a lot of Traits and I'm just wondering if I haven't taken a wrong turn and made it harder than it needs to be.

I want to use an endpoint with a Form that contains a file. This is fairly easy in Rocket using the TempFile struct. When I try to mark the endpoint with openapi, I have errors that JsonSchema, Deserialize, Serialize and Default are not implemented for TempFile. In order to implement the Traits, I have to create a local struct for TempFile because you are not allowed to implement a trait you didn't define for a struct you didn't define. Then you need to write code incorporating the functionality from the original struct into your struct. Below are the stubs that I have implemented to satisfy the compiler for now. In the current state, it complains that OpenApiFromData is not implemented for rocket::form::Form<ExampleForm<'_>>. To solve this it looks like I might have to declare a local struct and add all of the traits and functions to it that I need.

Am I going about this the right way?

Here is my code:

#[macro_use] extern crate rocket;
use rocket::serde::json::Json;
use std::path::Path;
use rocket::form::Form;
use rocket_okapi::{ openapi, routes_with_openapi };
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
use rocket::fs::TempFile;
use schemars::gen::SchemaGenerator;

///////////// This is the code I want to use //////////////////////////////////////////

#[derive(Serialize, Deserialize, FromForm, JsonSchema)]
pub struct Example {
    example_id:        u64,
}

#[derive(FromForm, JsonSchema, Debug, Default, Serialize, Deserialize)]
pub struct ExampleForm<'f> {
    example_data: ExampleTempFile<'f>,
}

#[openapi]
#[post("/example", format = "multipart/form-data", data = "<form>")]
pub async fn post_example(form: Form < ExampleForm < '_ > > ) -> std::result::Result<Json<Example>, String> {
    let example = Example {
        example_id: 1
    };
    Ok(Json(example))
}

#[rocket::main]
#[doc = "The main entry point for Rocket" ]
async fn main() -> Result <(), rocket::Error> {

    rocket::build()
        .mount("/", routes_with_openapi![post_example])
        .launch()
        .await
}


///////////// This is the supporting code stubs I think I need to fill out //////////

#[derive (Debug)]
struct ExampleTempFile<'a>(&'a mut TempFile<'a>);

impl ExampleTempFile<'_> {
    pub async fn persist_to<P>(&mut self, path: P) -> std::io::Result<()>
    where P: AsRef<Path>
    {
        self.0.persist_to(path).await
    }
}

impl<'de> Deserialize<'de> for  ExampleTempFile<'_> {
    fn deserialize<D>(_: D) -> Result<Self, <D as rocket::serde::Deserializer<'de>>::Error> where D: rocket::serde::Deserializer<'de> {
        Ok(ExampleTempFile { 0: &mut TempFile::Buffered { content: "" } })
    }
}

impl Serialize for ExampleTempFile<'_> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: rocket::serde::Serializer {
        serializer.serialize_bool(true)
    }
}

impl Default for ExampleTempFile<'_> {
    fn default() -> Self {
        ExampleTempFile{ 0: &mut TempFile::default().unwrap() }
    }
}

impl<'a> schemars::JsonSchema for ExampleTempFile<'a> {
    fn schema_name() -> String {
        "TempFile".to_owned()
    }
    fn json_schema( _: &mut SchemaGenerator ) -> schemars::schema::Schema {
        schemars::schema::SchemaObject::default().into()
    }
}

use rocket::form::FromFormField;
impl<'__f> FromFormField<'_> for ExampleTempFile<'__f> {
}

//////////// This is the bit where it looks like I might have to do the same trick with the local struct again //////////////////

use okapi::Map;
use rocket_okapi::{ gen::OpenApiGenerator, request::OpenApiFromData, Result as OpenApiResult };
use okapi::openapi3::{RequestBody};
impl<'r> OpenApiFromData<'r> for Form<ExampleForm<'r>> {
    fn request_body(gen: &mut OpenApiGenerator) -> OpenApiResult <RequestBody>{
        Ok(RequestBody {
            content: { Map::new() },
            required: true,
            ..Default::default()
        })
    }
}

Here is my Cargo.toml:

[package]
name = "example"
version = "0.1.0"
edition = "2018"

[dependencies]
rocket = { version = "0.5.0-rc.1", features = [ "json" ] }
serde = { version = "1.0.64", features = ["derive"] }
serde_json = "1.0.64"
log = "0.4.14"
async-global-executor = "2.0.2"
okapi = "0.6.0-alpha-1"
rocket_okapi = "0.7.0-alpha-1"
schemars = "^0.8"

Uuid in Parameter

I got it nearly compiling with #29 and the rocket master ;)

But i got still an error on Uuid in parameter:

error[E0277]: the trait bound `rocket_contrib::uuid::Uuid: OpenApiFromParam<'_>` is not satisfied
  --> src/api/auth.rs:29:1
   |
29 | #[openapi]
   | ^^^^^^^^^^ the trait `OpenApiFromParam<'_>` is not implemented for `rocket_contrib::uuid::Uuid`
   |
   = note: required by `path_parameter`
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

deserializing from json results in wrong structure

When deserializing from json the schemas from a param also get added to the extensions object of a param, resulting in faulty json being outputted when serializing again

use okapi::openapi3::{Operation, RefOr, Parameter};

fn main() {

    let json = "{\"responses\": {}, \"name\": \"someOp\", \"parameters\": [{\"in\": \"path\", \"schema\": {\"$ref\": \"#/defid\"}, \"name\": \"param1\"}]}";

    let operation: Operation = serde_json::from_str(json).unwrap();

    for param in &operation.parameters {
        match param {
            RefOr::Ref(_) => {
            }
            RefOr::Object(p) => {
                println!("p.json: {}", serde_json::to_string(p).unwrap());
                println!("p.value.json: {}", serde_json::to_string(&p.value).unwrap());
                println!("p.extensions.json: {}", serde_json::to_string(&p.extensions).unwrap());
            }
        }
    }

    println!("json: {}", serde_json::to_string(&operation).unwrap());

}

results in

p.json: {"name":"param1","in":"path","schema":{"$ref":"#/defid"},"schema":{"$ref":"#/defid"}}
p.value.json: {"schema":{"$ref":"#/defid"}}
p.extensions.json: {"schema":{"$ref":"#/defid"}}
json: {"parameters":[{"name":"param1","in":"path","schema":{"$ref":"#/defid"},"schema":{"$ref":"#/defid"}}],"responses":{},"name":"someOp"}

The same happens when deserializing an operation with responses, deserializing and serializing this

   "responses": {
      "200": {
        "description": "info to be returned",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/getInfoResultSchema"
            }
          }
        }
      },
      "default": {
        "description": "Unexpected error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/DefaultError"
            }
          }
        }
      }
    }

results in this

"responses": {
          "default": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DefaultError"
                }
              }
            }
          },
          "200": {
            "description": "info to be returned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/getInfoResultSchema"
                }
              }
            }
          },
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/getInfoResultSchema"
                }
              }
            },
            "description": "info to be returned"
          }
        }

Documenting query params

I'd like to use Okapi to document the query params in my Rocket Route. If I do the following:

#[openapi]
#[get("/?<id>")]
fn get_by_id(id: i32) -> String {
    format!("got {}", id)
}

then the resulting swagger has an empty Parameters section. I have tried switching to a form (which admittedly would make more sense because it allows you to add doc comments):

#[openapi]
#[derive(FromForm, JsonSchema)]
struct Query {
    /// This is the id that we will format very nicely for you.
    id: i32,
}

#[openapi]
#[get("/?<query..>)]
fn get_by_id(query: Query) -> String {
    format!("got {}", query.id)
}

This however yields the same results. Are query params not yet supported?

deserializing and serializing results in faulty json

When deserializing from json the schemas from a param also get added to the extensions object of a param, resulting in faulty json being outputted when serializing again (schema attribute is added twice)

use okapi::openapi3::{Operation, RefOr, Parameter};

fn main() {

    let json = "{\"responses\": {}, \"name\": \"someOp\", \"parameters\": [{\"in\": \"path\", \"schema\": {\"$ref\": \"#/defid\"}, \"name\": \"param1\"}]}";

    let operation: Operation = serde_json::from_str(json).unwrap();

    for param in &operation.parameters {
        match param {
            RefOr::Ref(_) => {
            }
            RefOr::Object(p) => {
                println!("p.json: {}", serde_json::to_string(p).unwrap());
                println!("p.value.json: {}", serde_json::to_string(&p.value).unwrap());
                println!("p.extensions.json: {}", serde_json::to_string(&p.extensions).unwrap());
            }
        }
    }

    println!("json: {}", serde_json::to_string(&operation).unwrap());

}

results in

p.json: {"name":"param1","in":"path","schema":{"$ref":"#/defid"},"schema":{"$ref":"#/defid"}}
p.value.json: {"schema":{"$ref":"#/defid"}}
p.extensions.json: {"schema":{"$ref":"#/defid"}}
json: {"parameters":[{"name":"param1","in":"path","schema":{"$ref":"#/defid"},"schema":{"$ref":"#/defid"}}],"responses":{},"name":"someOp"}

The same happens when deserializing an operation with responses, deserializing and serializing this

   "responses": {
      "200": {
        "description": "info to be returned",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/getInfoResultSchema"
            }
          }
        }
      },
      "default": {
        "description": "Unexpected error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/DefaultError"
            }
          }
        }
      }
    }

results in this

"responses": {
          "default": {
            "description": "Unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DefaultError"
                }
              }
            }
          },
          "200": {
            "description": "info to be returned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/getInfoResultSchema"
                }
              }
            }
          },
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/getInfoResultSchema"
                }
              }
            },
            "description": "info to be returned"
          }
        }

Implement JsonSchema for chrono::DateTime

Is it possible to implement JsonSchema for chrono::DateTime ?
I have structs

#[derive(Queryable, QueryableByName, JsonSchema, AsChangeset, Serialize, Deserialize)]     
#[serde(crate = "rocket::serde")]
#[table_name = "contents"]
pub struct Content {
      pub id: i32,
      pub title: String,
      pub story: String,
      pub published: DateTime<chrono::Utc>,     
      pub user_id: i32,
}
#[derive(Debug, Insertable, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")]
#[table_name = "contents"]
pub struct InsertableContent {
    pub title: String,
    pub story: String,
    #[serde(with = "chrono::serde::ts_seconds")]
    pub published: DateTime<chrono::Utc>,
    pub user_id: i32,
}

Compiling gives following errors

error[E0573]: expected type, found module `chrono::serde::ts_seconds`
  --> src/models.rs:23:20
   |
23 |     #[serde(with = "chrono::serde::ts_seconds")]
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type

error[E0277]: the trait bound `chrono::DateTime<chrono::Utc>: rocket_okapi::JsonSchema` is not satisfied
  --> src/models.rs:13:20
   |
13 |     pub published: DateTime<chrono::Utc>,
   |                    ^^^^^^^^^^^^^^^^^^^^^ the trait `rocket_okapi::JsonSchema` is not implemented for `chrono::DateTime<chrono::Utc>`

error[E0277]: the trait bound `chrono::DateTime<chrono::Utc>: rocket_okapi::JsonSchema` is not satisfied
   --> src/models.rs:6:38
    |
6   | #[derive(Queryable, QueryableByName, JsonSchema, AsChangeset, Serialize, Deserialize)]
    |                                      ^^^^^^^^^^ the trait `rocket_okapi::JsonSchema` is not implemented for `chrono::DateTime<chrono::Utc>`
    |
note: required by `rocket_okapi::JsonSchema::_schemars_private_is_option`
   --> /home/fs0c131y/.local/share/cargo/registry/src/github.com-1ecc6299db9ec823/schemars-0.8.6/src/lib.rs:372:5
    |
372 |     fn _schemars_private_is_option() -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the derive macro `JsonSchema` (in Nightly builds, run with -Z macro-backtrace for more info)

Some errors have detailed explanations: E0277, E0573.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `content_service` due to 3 previous errors

Query String parameters

Can query string parameters be described? If not, how much work would it be to add support for them?

Document or provide examples for more complex error handling

Hello! I am new to Rust and have recently learned about okapi. I am trying to use it for a REST API with a mongodb backend. I would like to properly handle and report mongodb-related failures as a HTTP 500 error, but I cannot figure out how to do that. I suppose I could implement OpenApiResponder for the mongodb errors, but it is not clear to me how to properly implement or how I would set up the return type for my handler. An example or more documentation would be very helpful =)

Support multiple content types per path

When attempting to specify two routes with the same path and method, but different accepted format (e.g. format = "application/json" vs format = "application/cbor") error message appears: An OpenAPI operation has already been added for ...

The reason is that currently only method and path are taken into account when adding a new routes, while format should be considered as well.

(Thanks a lot for a nice crate!)

Name collision on request/response objects

When two routes have the same name for a Request / Response the namespaces are clobbered. Example:

https://github.com/leeola/example_okapi_name_collision (specifically this file) will incorrectly report that the /two route has a response type of:

{
  "reply": "string"
}

Instead of what it should be,

{
  "different_schema": "string"
}

I'm happy to help developing a solution to this, but I'm unsure how best it can be handled. Ideally, I imagine something resembling idiomatic OpenAPI specs should be generated. Though, looking at the classic PetStore example it looks like that entire bottom area is ripe for having many structure names occupy the same namespace.

Thoughts on how best to handle this?

Create a new release bc of the schmears update

Please create a new release of okapi/rocket_okapi because the current one still tries to use the old 0.1.x schemars.

If you update a dependency you should bump the version number and publish it on crates.io.

Please :)

Responding with statuses other than 201, 202, 400 and 404

Reading through the code, it seems like okapi only implements the aforementioned status codes in response schema generation. (https://github.com/GREsau/okapi/blob/master/rocket-okapi/src/response/responder_impls.rs ). Are there plans / interest to add full support for the entire range of possible status messages (e.g. probably adding a responder impl for rocket::http::Status.

I tried implementing something but my macro skills aren't really up to par, and it isn't compiling. (master...xylix:extend-status-code-support )

I could also be misreading Rocket's status classes, but am unsure in what way.

Route description

It seems that route docs doesn't currently used to generate route descriptions.
Am I missing anything?

Thanks for the project!

form field not supported

I have an api with a parameter async. This is a reserved word, so to handle this I have the following form defined, with the form field statement specifying that the variable is_async is called "async" in the API.

#[derive(FromForm, JsonSchema, Debug)]
struct MoveInput {
    to: String,
    #[form(field = "async")]
    is_async: Option<bool>
}

#[openapi]
#[post("/move/?<input..>")]
fn mv(input: Form<MoveInput>, session: State<Session>) {

in the swagger UI this is still shown as is_async.

Cannot use the openapi annotation with any of the rocket typed stream response types

Hi,

Thank you so much for this library! It really is quite impressive what you have implemented thus far!

This issue is alluded to in #52 but I have observed that this seems to be a larger issue impacting all of the typed streams in rocket 0.5.0-rc.1. I hit the same issue mentioned in #52 but I saw that OpenApiResponderInner had already been implemented for TextStream<S>, ReaderStream<S>, and ByteStream<S so I decided to see if TextStream would work for my use case. The result is the same compiler error encountered with EventStream!:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types

The EventStream! and other typed streams return types ultimately expand to a type like the following and they trip up the openapi macro because it can't just reuse the type as defined.

impl rocket::futures::stream::Stream<Item = rocket::response::stream::Event>

I pulled your latest code and dug around a bit and made an attempt at a fix but I didn't see a clear path forward. In the case of TextStream and ByteStream, I could see where the openapi macro could rewrite the type to one of the string or byte representations that already have an implementation of OpenApiResponderInner. For EventStream, I was thinking along the same lines and tried rewriting the type as the rocket Event type; however, this type doesn't implement rocket::response::Responder so that looked like a dead end.

One alternative I was thinking might be possible would be to add an optional field to the openapi attribute that allows the developer to specify a type to substitute in place of the type that the typed stream macros expand to. I obviously don't have the same insight into the inner workings so this may be a terrible idea!

If you have some guidance on how you would like to see this functionality implemented I would be glad to take on this effort!

Thanks!

Cannot use rocket::response::stream::EventStream with okapi

Hi,

First of all thanks for contributing okapi to the world!

I just tried to use the first EventStream example from the Rocket documentation decorated with #[openapi] and ran into the following error:

cargo build
   Compiling example v0.1.0 (...)
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/main.rs:54:16
   |
54 | fn stream() -> EventStream![] {
   |                ^^^^^^^^^^^^^^
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

It compiles just fine when I use #[openapi(skip)] instead of #[openapi]. But do you have any idea how to make the example work with #[openapi]? Any help would be highly appreciated!

AsyncAPI

Feature request:
Add support for AsyncAPI as well as OpenAPI. This would allow WebSocket based APIs to be documentable as well. These standards complement each other, and from what I can tell, they mimic each other, but they don't overlap in functionality other than maybe type schemas, which should have the same model in both standards.

PathBuf parameters are not supported

I have a function where I take an input path like this:

#[openapi]
#[get("/<path..>")]
fn info(path: PathBuf, session: State<Session>) -> String {
    format!("info {:?}", path)
}

In the swagger ui, that is displayed as
bild

So there is no parameter listed.

Note, this is with the following versions:
rocket = "0.4.7"
rocket_okapi = "0.6.0-alpha-1"
schemars = "0.7"
okapi = { version = "0.5.0-alpha-1", features = ["derive_json_schema"] }

Visibility of routes

Where a route is declared as a pub fn, Rocket creates a handlers that is also declared as pub fn. Currently, marking a route with #[openapi] sets the route to private, making it impossible to generate documentation for routes that exists in another module.

Found conflicting responses keys while merging

(This is an issue for when people have this issue in the future)

I'm getting the warning:

WARN :okapi::merge - Found conflicting responses keys while merging, they have the same name but different values for `401`: 
Object(Response { .... })
Object(Response { .... })

How do I resolve this?

Support Rocket 0.5

Hi !
Rocket has released 0.5 in RC-1, can you support it ?

I had to disable okapi because Rocket 0.5 support stable channel of Rust and using actual version of this crate supports only previous Rocket and so it requires rust nightly

See my migration where I had to disable okapi: mountains/permafrost@e7b5476

Edit: migration done with success: mountains/permafrost@4d53f99

Retrieve OpenApi object after generating

Currently there is no easy way to get the OpenApi object or the generated file without starting rocket.

I made a small (hacky) workaround to get the OpenApi object without starting rocket.
Here are some code snippets if someone has the same issue. But it would be code if this was supported in the crate.

Somewhere in my code:

pub fn get_openapi() -> OpenApi{
    generate_openapi_file![
        //...add all calls that are also inside `routes_with_openapi`..
    ]
}

Rocket_okapi_codegen/src/lib.rs

#[proc_macro]
pub fn generate_openapi_file(input: TokenStream) -> TokenStream {
    routes_with_openapi::parse_openapi_file(input)
}

Rocket_okapi_codegen/src/routes_with_openapi/mod.rs

pub fn parse_openapi_file(routes: TokenStream) -> TokenStream {
    get_openapi_file(routes)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}

// Basically a modified `parse_inner` with some small changes 
// (there is some custom code like `get_new_openapi_object` here)
fn get_openapi_file(routes: TokenStream) -> Result<TokenStream2>{
    let paths = <Punctuated<Path, Comma>>::parse_terminated.parse(routes)?;
    let add_operations = create_add_operations(paths)?;
    let openapi_object = get_new_openapi_object();
    Ok(quote! {
        {
            let settings = ::rocket_okapi::settings::OpenApiSettings::new();
            let mut gen = ::rocket_okapi::gen::OpenApiGenerator::new(settings.clone());
            #add_operations
            #openapi_object
            // It does not return the routes here, but the spec instead.
            spec
        }
    })
}

Like I said this is a bit of a hack. But a native way would be nice.

How to derive JsonSchema for Json<> structs

I am trying to use okapi with a custom Responder for a Json<> wrapped struct. I am getting this error:

   Compiling openapi-responder v0.1.0 (/home/richard/small_test_projects/openapi_responder)
error[E0277]: the trait bound `rocket::serde::json::Json<Example>: JsonSchema` is not satisfied
  --> src/main.rs:20:12
   |
20 |     inner: Json<Example>,
   |            ^^^^^^^^^^^^^ the trait `JsonSchema` is not implemented for `rocket::serde::json::Json<Example>`
   |
   = note: required by `add_schema_as_property`

Here is my Cargo.toml:

[package]
name = "openapi-responder"
version = "0.1.0"
edition = "2018"

[dependencies]
rocket = { version = "0.5.0-rc.1", features = [ "json" ] }
serde = { version = "1.0.64", features = ["derive"] }
serde_json = { version = "1.0.64" }
okapi = "0.6.0-alpha-1"
rocket_okapi = "0.7.0-alpha-1"
rocket_okapi_codegen = "0.7.0-alpha-1"
schemars = "^0.8"

Here is my main.rs:

#[macro_use]
extern crate rocket;
extern crate rocket_okapi;
use rocket_okapi::{openapi, routes_with_openapi, OpenApiError, response::OpenApiResponderInner, gen::OpenApiGenerator, util::add_schema_response};
use okapi::openapi3::Responses;

use rocket::serde::json::Json;
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;

#[derive(Serialize, Deserialize, JsonSchema)]
pub struct Example {
    error: String,
}

#[derive(Responder, JsonSchema)]
#[response(content_type = "json", status=200)]
pub struct ExampleResponse {
    inner: Json<Example>,
}

#[openapi]
#[get("/example_response", format="application/json")]
pub async fn get_example_response() -> ExampleResponse {
    ExampleResponse { inner: Json(Example { error: "hi".to_owned() } ) }
}

impl OpenApiResponderInner for ExampleResponse {
    fn responses(gen: &mut OpenApiGenerator) -> Result<Responses, OpenApiError>{
        let mut responses = Responses::default();
        let schema = gen.json_schema::<Json<Example>>();
        add_schema_response(&mut responses, 200, "application/json", schema)?;
        Ok(responses)
    }
}

#[rocket::main]
#[doc = "The main entry point for Rocket" ]
async fn main() -> Result <(), rocket::Error> {
    rocket::build()
        .mount("/", routes_with_openapi![get_example_response])
        .launch()
        .await
}

I don't understand how I can generate the schema for a Json struct. I can't use the derive(JsonSchema) attribute because it's not a struct, enum or union.

Okapi emits warnings when using a closure with no arguments

When writing a closure with no arguments, Okapi emits a warning on compilation.

#[openapi]
#[get("/?<id>")]
fn get_by_id(id: Option<i32>) -> String {
    let default = || 1;
    let id = id.unwrap_or_else(default);
    format!("got {}", id)
}

This gives the following result:

warning: unnecessary parentheses around type
  --> src/main.rs:16:1
   |
16 | #[get("/?<id>")]
   | ^^^^^^^^^^^^^^^^ help: remove these parentheses
   |
   = note: `#[warn(unused_parens)]` on by default

warning: 1 warning emitted

I've looked at the emitted code using cargo expand, but i couldn't figure out the cause of this warning.

Unable to deserialize and then serialize SecurityScheme into JSON

Hi. There is problem with deserializing and then serializing security scheme into JSON. I have a code which parse spec from YAML, then attempt to serialize it into both YAML and JSON. YAML is valid, but JSON produces duplicated fields type and scheme:

use okapi::openapi3::OpenApi;

static SPEC_ROOT: &str = r##"openapi: 3.0.3
info:
  title: CARDI API
  version: 0.14.0
paths: {}
security:
  - BasicAuth: []
components:
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
"##;

let mut spec: OpenApi = serde_yaml::from_str(SPEC_ROOT).unwrap();
println!(
    "DEBUG: {:#?}\nJSON: {}\nYAML: {}", 
    spec, 
    serde_json::to_string_pretty(&spec).unwrap(), 
    serde_yaml::to_string(&spec).unwrap()
);

Problem is that fields type and scheme ends up in both data and extensions fields. Since it looks like some serde limitation/bug, proper solution could be custom deserialization. If this approach is OK, I could try to implement it.

I believe this might be related to #74.

Debug output

DEBUG: OpenApi {
    openapi: "3.0.3",
    info: Info {
        title: "CARDI API",
        description: None,
        terms_of_service: None,
        contact: None,
        license: None,
        version: "0.14.0",
        extensions: {},
    },
    servers: [],
    paths: {},
    components: Some(
        Components {
            schemas: {},
            responses: {},
            parameters: {},
            examples: {},
            request_bodies: {},
            headers: {},
            security_schemes: {
                "BasicAuth": Object(
                    SecurityScheme {
                        description: None,
                        data: Http {
                            scheme: "basic",
                            bearer_format: None,
                        },
                        extensions: {
                            "scheme": String(
                                "basic",
                            ),
                            "type": String(
                                "http",
                            ),
                        },
                    },
                ),
            },
            links: {},
            callbacks: {},
            extensions: {},
        },
    ),
    security: [
        {
            "BasicAuth": [],
        },
    ],
    tags: [],
    external_docs: None,
    extensions: {},
}

JSON output (invalid)

{
  "openapi": "3.0.3",
  "info": {
    "title": "CARDI API",
    "version": "0.14.0"
  },
  "paths": {},
  "components": {
    "securitySchemes": {
      "BasicAuth": {
        "type": "http",
        "scheme": "basic",
        "scheme": "basic",
        "type": "http"
      }
    }
  },
  "security": [
    {
      "BasicAuth": []
    }
  ]
}

YAML output (ok)

---
openapi: 3.0.3
info:
  title: CARDI API
  version: 0.14.0
paths: {}
components:
  securitySchemes:
    BasicAuth:
      scheme: basic
      type: http
security:
  - BasicAuth: []

Cannot build project with okapi as dependency

I'm trying to setup okapi for rocket 0.5.0-rc.1.
My Cargo.toml file is the following:

[package]
name = "food-organizer"
version = "0.1.0"
edition = "2018"

[dependencies]
# Env
dotenv = "0.15.0"

# Web server
rocket = { version = "0.5.0-rc.1", features=["tls", "json"] }
rocket_cors = "0.5.2"

# API documentation
okapi = "0.7.0-alpha-1"
rocket_okapi = { version = "0.8.0-alpha-1"}
schemars = { version = "0.8.6", features = ["preserve_order"] }

# Scraper
reqwest = "0.11.4"
scraper = "0.12.0"

# Serialisation
serde = "1.0.130"
serde_json = "1.0.68"

# Utils
regex = "1.5.4"
jsonwebtoken = "7.2.0"
chrono = "0.4.19"
bcrypt = "0.10.1"

# OpenSSL
openssl = {version="0.10.36", features=["vendored"]}

# DB driver
diesel = { version = "1.4.8", features = ["sqlite"] }

[patch.crates-io]
rocket = { git = 'https://github.com/SergioBenitez/Rocket', branch = "v0.5-rc" }
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors.git", branch = "master" }
rocket_okapi = { git = "https://github.com/GREsau/okapi", branch = "master" }
okapi = { git = "https://github.com/GREsau/okapi", branch = "master" }

I'm trying to build and I get the same error again and again, like if okapi wasn't using rocket 0.5 :

   Compiling rocket_okapi v0.8.0-alpha-1 (https://github.com/GREsau/okapi?branch=master#867e5061)
error[E0432]: unresolved import `rocket::response::content::Custom`
 --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/handlers/content.rs:2:24
  |
2 | use rocket::response::{content::Custom, Responder};
  |                        ^^^^^^^^^^^^^^^ no `Custom` in `response::content`

error[E0432]: unresolved import `rocket::response::content::Custom`
 --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/handlers/openapi.rs:3:5
  |
3 | use rocket::response::content::Custom;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `Custom` in `response::content`

error[E0412]: cannot find type `Css` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:217:27
    |
217 | response_content_wrapper!(Css, "text/css");
    |                           ^^^ not found in `rocket::response::content`

error[E0412]: cannot find type `Custom` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:218:27
    |
218 | response_content_wrapper!(Custom, "*/*");
    |                           ^^^^^^ not found in `rocket::response::content`
    |
help: consider importing this struct
    |
1   | use rocket::response::status::Custom;
    |

error[E0412]: cannot find type `Html` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:219:27
    |
219 | response_content_wrapper!(Html, "text/html");
    |                           ^^^^ not found in `rocket::response::content`

error[E0412]: cannot find type `JavaScript` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:220:27
    |
220 |   response_content_wrapper!(JavaScript, "application/javascript");
    |                             ^^^^^^^^^^ help: a struct with a similar name exists: `RawJavaScript`
    |
   ::: /home/alexandre/.cargo/git/checkouts/rocket-8bf16d9ca7e90bdc/e382bc5/core/lib/src/response/content.rs:69:1
    |
69  | / ctrs! {
70  | |     // FIXME: Add a note that this is _not_ `serde::Json`.
71  | |     RawJson: JSON, "JSON", "application/json",
72  | |     RawXml: XML, "XML", "text/xml",
...   |
77  | |     RawJavaScript: JavaScript, "JavaScript", "application/javascript"
78  | | }
    | |_- similarly named struct `RawJavaScript` defined here

error[E0412]: cannot find type `Json` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:221:27
    |
221 | response_content_wrapper!(Json, "application/json");
    |                           ^^^^ not found in `rocket::response::content`
    |
help: consider importing one of these items
    |
1   | use crate::request::from_data_impls::Json;
    |
1   | use rocket::serde::json::Json;
    |

error[E0412]: cannot find type `MsgPack` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:222:27
    |
222 | response_content_wrapper!(MsgPack, "application/msgpack");
    |                           ^^^^^^^ not found in `rocket::response::content`

error[E0412]: cannot find type `Plain` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:223:27
    |
223 | response_content_wrapper!(Plain, "text/plain");
    |                           ^^^^^ not found in `rocket::response::content`

error[E0412]: cannot find type `Xml` in module `rocket::response::content`
   --> /home/alexandre/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/867e506/rocket-okapi/src/response/responder_impls.rs:224:27
    |
224 | response_content_wrapper!(Xml, "text/xml");
    |                           ^^^ not found in `rocket::response::content`

Some errors have detailed explanations: E0412, E0432.
For more information about an error, try `rustc --explain E0412`.
error: could not compile `rocket_okapi` due to 10 previous errors

Does anyone have an idea about how I can make this work?

Query parameters show up as camelCase but rocket expects snake_case

Given the following handler:

#[openapi(tag = "users")]
#[get("/?<page>&<sort_key>&<sort_direction>")]
pub async fn list_users(
    page: Option<usize>,
    sort_key: Option<UserSortKey>,
    sort_direction: Option<SortDirection>,
) -> Result<Json<Vec<User>>, AppError> { }

The resulting spec contains the following parameters array:

"parameters": [
  {
    "name": "page",
    "in": "query",
    "schema": {
      "type": "integer",
      "format": "uint",
      "minimum": 0.0
    }
  },
  {
    "name": "SortKey",
    "in": "query",
    "schema": {
      "$ref": "#/components/schemas/UserSortKey"
    }
  },
  {
    "name": "sortDirection",
    "in": "query",
    "schema": {
      "$ref": "#/components/schemas/SortDirection"
    }
  }
],

The names in the spec are all written in camelCase, however rocket expects the keys of the query params to be written in snake_case.
Can we adjust okapi to mirror the format rocket expects?

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.