GREsau / okapi

OpenAPI (AKA Swagger) document generation for Rust projects
MIT License
578 stars 103 forks source link

Incorrect openapi.json Generated for Response with Tuple #127

Closed MicaiahReid closed 11 months ago

MicaiahReid commented 1 year ago

Hi! I think I've found a bug with the generated openapi.json file when my rocket server has a response type with a tuple. I've slightly modified the baseline example in the docs to change the Response type to return a struct containing a tuple:

use rocket::serde::json::Json;
use rocket::{get};
use rocket_okapi::swagger_ui::{make_swagger_ui, SwaggerUIConfig};
use rocket_okapi::{openapi, openapi_get_routes, JsonSchema};

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

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

fn get_docs() -> SwaggerUIConfig {
    SwaggerUIConfig {
        url: "/my_resource/openapi.json".to_string(),
        ..Default::default()
    }
}

fn main() {
    rocket::build()
        .mount("/my_resource", openapi_get_routes![my_controller])
        .mount("/swagger", make_swagger_ui(&get_docs()))
        .launch();
}

This generates the following openapi.json file:

{
  "openapi": "3.0.0",
  "info": {
    "title": "test-swagger",
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "/my_resource"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "my_controller",
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Response": {
        "type": "object",
        "required": [
          "reply"
        ],
        "properties": {
          "reply": {
            "type": "array",
            "items": [
              {
                "type": "integer",
                "format": "uint64",
                "minimum": 0.0
              },
              {
                "type": "integer",
                "format": "uint64",
                "minimum": 0.0
              }
            ],
            "maxItems": 2,
            "minItems": 2
          }
        }
      }
    }
  }
}

Whenever I import this to editor.swagger.io, I get the following error:

Structural error at components.schemas.Response.properties.reply.items
should be object
Semantic error at components.schemas.Response.properties.reply.items
`items` must be an object

I believe that, for this tuple type of (u64, u64), this:

          "reply": {
            "type": "array",
            "items": [
              {
                "type": "integer",
                "format": "uint64",
                "minimum": 0.0
              },
              {
                "type": "integer",
                "format": "uint64",
                "minimum": 0.0
              }
            ],
            "maxItems": 2,
            "minItems": 2
          }

should have actually been generated as

          "reply": {
            "type": "array",
            "items": {
                "type": "integer",
                "format": "uint64",
                "minimum": 0.0
            },
            "maxItems": 2,
            "minItems": 2
          }

Is this a bug with the spec generation? Or is there something I'm doing wrong?

Thanks for the awesome tool and all of the work y'all are doing!

ralpha commented 1 year ago

Quickly checked. I'm not sure, but think this is a bug yes:

The value of "items" MUST be a valid JSON Schema. https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-00#section-10.3.1.2

This does not say list/array of JSON Schema(s).

Maybe prefixItems https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-00#section-10.3.1.1 Should be used instead. But will have to read up on it.

But this again is something in Schemars (different spec from OpenAPI spec), I know it is confusing and they are closely related in this case. So open issue in Schemars too https://github.com/GREsau/schemars/issues.

You can link back and include this info so it can be resolved quicker.

GREsau commented 11 months ago

OpenAPI 3.0.X uses (an extension of) the JSON Schema Specification Wright Draft 00, which allows "items" to be an array - see https://spec.openapis.org/oas/v3.0.0#schemaObject and https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-5.9

OpenAPI 3.1.0 uses the newer JSON Schema Draft 2020-12, which schemars (and by extension, okapi) does not yet support.

So for OpenAPI 3.0.0, which is what okapi currently produces, I believe the existing behaviour is correct