quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.8k stars 2.68k forks source link

Uni and Multi should not be represented in OpenAPI schema #8811

Closed emmanuelbernard closed 4 years ago

emmanuelbernard commented 4 years ago

When using

@GET
@Path("/{name}")
public Uni<Fruit> getOne(@PathParam(value = "name") String name) {
}

The schema is

UniFruit:
  type: object

Which is wrong. Uni and Multi should not be in the open api contract.

See https://stackoverflow.com/questions/61394139/openapi-spec-for-reactive-rest-service-using-quarkus

@cescoffier @kenfinnigan

quarkusbot commented 4 years ago

/cc @EricWittmann

bwoester commented 4 years ago

Out of the box support for Uni and Multi would be great.

I'm wondering though if this could be made configurable (with the out of the box behavior being default configuration). From the top of my head, I can see another similar use cases where I might like to tweak the generated OpenAPI schema, but there might be many more:

No matter whether my API returns a Set<Fruit> or a List<Fruit> or a Collection<Fruit>. To the consumer, the data is represented as a an array of fruit objects. I might want to map all of them to a single reference schema instead of generating different ones which in essence all define the same schema.

cescoffier commented 4 years ago

Yes: Multi would be an array, and Uni just the item type (Fruit)

cescoffier commented 4 years ago

There is an SPI to implement: https://github.com/smallrye/smallrye-open-api/tree/16ed0464e2f67018c31fc621b44e5eb4ea2c41fb/core/src/main/java/io/smallrye/openapi/runtime/scanner/spi

kenfinnigan commented 4 years ago

/cc @phillip-kruger

Do we need to add support for these types explicitly in SmallRye OpenAPI?

kenfinnigan commented 4 years ago

For endpoints defined as:

    @GET
    @Path("/uni")
    public Uni<String> uni() {
        return Uni.createFrom().item("Hello from Uni");
    }

    @GET
    @Path("/multi")
    public Multi<String> multi() {
        return Multi.createFrom().items("Hello", "from", "Multi");
    }

    @GET
    @Path("/uniType")
    public Uni<ComponentType> uniType() {
        return Uni.createFrom().item(this::createComponent);
    }

    @GET
    @Path("/multiType")
    public Multi<ComponentType> multiType() {
        return Multi.createFrom().items(createComponent(), createComponent());
    }

I've got OpenAPI definition of:

    "/test/multi": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/test/multiType": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ComponentType"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/test/uni": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/test/uniType": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ComponentType"
                }
              }
            }
          }
        }
      }
    },

Is that correct?

emmanuelbernard commented 4 years ago

Yes sounds like it is what should happen