Giter Club home page Giter Club logo

smallrye-open-api's Introduction

Contributing

Want to contribute? Great! We try to make it easy, and all contributions, even the smaller ones, are greatly welcome. This includes bug reports, fixes, documentation.

All SmallRye projects use GitHub Issues to manage issues. Open an issue directly in GitHub within the appropriate SmallRye project repository.

Becoming a Project Committer

Through continued contributions to SmallRye projects, other committers on the project can nominate you to become a committer too!

Check out the nomination process for full details.

All original contributions to SmallRye projects are licensed under the ASL - Apache License, version 2.0 or later, or, if another license is specified as governing the file or directory being modified, such other license.

All contributions are subject to the Developer Certificate of Origin (DCO). The DCO text is also included verbatim in the dco.txt file in the root directory of each repository.

Before you Contribute

To contribute, use GitHub Pull Requests, from your own fork.

Code Reviews

All submissions, including submissions by project members, need to be reviewed before they are merged.

Continuous Integration

We’re all human, so SmallRye projects use continuous integration to ensure consistency, particularly as most SmallRye projects need to pass the applicable MicroProfile TCK for that specification. Each pull request triggers a full build of the project. Please make sure to monitor the output of the build and act accordingly.

Tests and Documentation are not optional

Don’t forget to include tests in your pull requests. Also, don’t forget the documentation (Javadoc).

Setup

If you have not done so on your machine, you need to:

  • Install Git and configure your GitHub access

  • Install Java SDK (OpenJDK recommended)

  • Install Maven

IDE Config and Code Style

SmallRye projects have a strictly enforced code style. Code formatting is done by the Eclipse code formatter, using the config files found in Code Rules. By default when you run mvn install the code will be formatted automatically. When submitting a pull request the CI build will fail if running the formatter results in any code changes, so it is recommended that you always run a full Maven build before submitting a pull request.

Eclipse Setup

Open the Preferences window, and then navigate to JavaCode StyleFormatter. Click Import and then select the eclipse-format.xml file in the coderules directory.

Next navigate to JavaCode StyleOrganize Imports. Click Import and select the eclipse.importorder file.

IDEA Setup

Open the Preferences window, navigate to Plugins and install the [Eclipse Code Formatter Plugin](https://plugins.jetbrains.com/plugin/6546-eclipse-code-formatter).

Restart your IDE, open the Preferences window again and navigate to Other SettingsEclipse Code Formatter.

Select Use the Eclipse Code Formatter, then change the Eclipse Java Formatter Config File to point to the eclipse-format.xml file in the coderules directory. Make sure the Optimize Imports box is ticked, and select the eclipse.importorder file as the import order config file.

Signing Commits

Signing commits is required to make sure that the contributor matches the author. To be able to sign commits, use the following instructions: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits

The small print

This project is an open source project, please act responsibly, be nice, polite, and enjoy!

smallrye-open-api's People

Contributors

abatalev avatar agentgonzo avatar anarsultanov avatar azquelt avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar devnied avatar ericwittmann avatar fabiobrz avatar fromage avatar gastaldi avatar hbelmiro avatar jmini avatar kenfinnigan avatar ladicek avatar lamtrhieu avatar lucamolteni avatar mikeedgar avatar msavy avatar msmiths avatar pferraro avatar phillip-kruger avatar postremus avatar radcortez avatar scottcurtis2605 avatar smallrye-ci avatar snazy avatar tarilabs avatar tjquinno 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  avatar  avatar  avatar  avatar

smallrye-open-api's Issues

Enum fields are included in schema

I am trying to generate schema for an Enum type:

public enum JobState {
    DONE,
    FAILED,
    PROCESSING(FAILED, DONE),
    QUEUED(PROCESSING);

    private final JobState[] targetStates;

    JobState(final JobState... targetStates) {
        this.targetStates = targetStates;
    }
    ...
}

Unfortunately, currently this results in the targetStates field being included in the enumeration of the schema:

              state:
                enum:
                - DONE
                - FAILED
                - PROCESSING
                - QUEUED
                - targetStates
                type: string

@NotNull should lead to "required" in a data structure

Using a @NotNull annotation in a data structure should create a "required" entry in the open api structure, but it currently does not.

Example

public class MyCommand {
    @NotNull
    @JsonbProperty("date")
    private LocalDate date;
    @Nullable
    @JsonbProperty("reason")
    private String reason;
}

Should have "required" array entry:

MyCommand:
  type: object
  required:
    - date
  properties:
    date:
      $ref: '#/components/schemas/LocalDate'
    reason:
      type: string

But currently is:

MyCommand:
  type: object
  properties:
    date:
      $ref: '#/components/schemas/LocalDate'
    reason:
      type: string

OpenAPI hidden property not hidden

The following POJO annotated with a property declared as hidden in OpenAPI (@Schema(hidden = true)) is still visible in the final OpenAPI document

public class MyOpenApiEntity {

@Schema(hidden = false)
private String visibleProperty;

@Schema(hidden = true)
private String hiddenProperty;

public String getVisibleProperty() {
return visibleProperty;
}
public String getHiddenProperty() {
return hiddenProperty;
}
}
In SwaggerUI it looks like this, i.e. the hidden property is visible which is wrong.

quakus-hiddenproperty

The openAPI yaml file looks like this:

components:
schemas:
MyOpenApiEntity:
properties:
hiddenProperty: {}
visibleProperty:
type: string
(I guess that the hiddenProperty shouldn't be there at all)

This code was tested on macOS Mojave and OpenJDK Runtime Environment 18.9 (build 11+28) and Quarkus 0.14.0

@Parameter with missing name produces duplicate

Name is missing in the @Parameter:

public Response deleteTask(
@Parameter(
            description = "The id of the task",
            example = "e1cb23d0-6cbe-4a29",
            schema = @Schema(
                    type = SchemaType.STRING))
 @PathParam("taskId")
String taskId) {
    /* .. */
}

produces:

      parameters:
      - in: path
        description: The id of the task
        schema:
          type: string
        example: e1cb23d0-6cbe-4a29
      - name: taskId
        in: path
        required: true
        schema:
          type: string

=> Only one parameter should be generated.


An other related problem, name is present:

public Response deleteTask(
@Parameter(
            description = "The id of the task",
            name = "taskId",
            example = "e1cb23d0-6cbe-4a29",
            schema = @Schema(
                    type = SchemaType.STRING))
 @PathParam("taskId")
String taskId) {
    /* .. */
}

produces:

      parameters:
      - name: taskId
        in: path
        description: The id of the task
        schema:
          type: string
        example: e1cb23d0-6cbe-4a29

This is not valid because required : true is missing. This is mandatory for path parameter in OpenAPI

Schemas generated from scanned objects missing type="object"

I am doing some work on #73 and I noticed that schema entries generated from scanned objects are missing the "type": "object" attribute in the resulting document. From what I have read, it seems that omission of the type technically results in the schema being very permissive, which I do not think is desired in this scenario.

What are the thoughts of the development team on having the annotation scan process also generate a type attribute on object schemas added to the components list? Changing the process to generate it would result in breakage for several unit tests which would need to be adjusted as a result.

[1.1] ModelConstructionTckTest is not executing any tests

As discussed here: #44 (comment)

ModelConstructionTckTest is green because none of the tests are executed.
I guess this is a TestNG / JUnit issue...

If you revert some changes made with 24d4fd7 the test should fail.

The maven build is running JUnit Surefire and the TCK Tests are written with TestNG (@org.testng.annotations.Test). The tests are ignored.

If you run it inside your IDE with the TestNG runner, then you see test results. I can not run the class with the JUnit runner in my IDE.

Add a toString() to OpenAPIImpl

I can see the following information in the logs:

2018-10-31 14:32:09,326 INFO  [io.smallrye.openapi.api.OpenApiDocument] (ServerService Thread Pool -- 5) OpenAPI document initialized: io.smallrye.openapi.api.models.OpenAPIImpl@15695af8

It would be nice if OpenAPIImpl had a toString() to show useful information instead

OpenApiAnnotationScanner throws StringIndexOutOfBoundsException on primitive array types

Given a JAX-RS response class that provides data as an array of primitives, an exception is always thrown.

@Schema(name = "MyResponse", description = "the REST response class"
public class MyResponse {
    @Schema(required = true, description = "a packed data array")
    private double[] data;

    // ... getters and setters removed
}

Then a given a simple jax-rs service

@Path("/v1")
public class MyResource {
    @GET
    @Operation(summary = "get a response")
    @APIResponses({@APIResponse(responseCode="200", 
                                content = @Content(mediaType = "application/json", 
                                                                   schema = @Schema(implementationClass = MyResponse.class)))})
    public MyResponse getResponse() {
        return new MyResponse();
    }
}

This returns the following stacktrace

15:46:27,679 ERROR [io.qua.dev.DevModeMain] Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
        [error]: Build step io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#build threw an exception: java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 6
        at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:141)
        at io.quarkus.dev.DevModeMain.doStart(DevModeMain.java:171)
        at io.quarkus.dev.DevModeMain.main(DevModeMain.java:89)
Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
        [error]: Build step io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#build threw an exception: java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 6
        at io.quarkus.builder.Execution.run(Execution.java:108)
        at io.quarkus.builder.BuildExecutionBuilder.execute(BuildExecutionBuilder.java:121)
        at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:115)
        at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:107)
        ... 2 more
Caused by: java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 6
        at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3319)
        at java.base/java.lang.String.substring(String.java:1874)
        at io.smallrye.openapi.runtime.scanner.FilteredIndexView.accepts(FilteredIndexView.java:67)
        at io.smallrye.openapi.runtime.scanner.FilteredIndexView.getClassByName(FilteredIndexView.java:103)
        at org.jboss.jandex.CompositeIndex.getClassByName(CompositeIndex.java:190)
        at io.smallrye.openapi.runtime.scanner.dataobject.AugmentedIndexView.getClass(AugmentedIndexView.java:43)
        at io.smallrye.openapi.runtime.scanner.dataobject.AugmentedIndexView.containsClass(AugmentedIndexView.java:47)
        at io.smallrye.openapi.runtime.scanner.dataobject.IgnoreResolver$JsonIgnoreTypeHandler.shouldIgnore(IgnoreResolver.java:226)
        at io.smallrye.openapi.runtime.scanner.dataobject.IgnoreResolver.isIgnore(IgnoreResolver.java:72)
        at io.smallrye.openapi.runtime.scanner.OpenApiDataObjectScanner.depthFirstGraphSearch(OpenApiDataObjectScanner.java:223)
        at io.smallrye.openapi.runtime.scanner.OpenApiDataObjectScanner.process(OpenApiDataObjectScanner.java:190)
        at io.smallrye.openapi.runtime.scanner.OpenApiDataObjectScanner.process(OpenApiDataObjectScanner.java:141)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.introspectClassToSchema(OpenApiAnnotationScanner.java:1820)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.readClassSchema(OpenApiAnnotationScanner.java:1803)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.readSchema(OpenApiAnnotationScanner.java:1757)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.readSchema(OpenApiAnnotationScanner.java:1701)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.readMediaType(OpenApiAnnotationScanner.java:1535)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.readContent(OpenApiAnnotationScanner.java:1499)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.readResponse(OpenApiAnnotationScanner.java:1665)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.processJaxRsMethod(OpenApiAnnotationScanner.java:622)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.processJaxRsResourceClass(OpenApiAnnotationScanner.java:362)
        at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.scan(OpenApiAnnotationScanner.java:200)
        at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.generateAnnotationModel(SmallRyeOpenApiProcessor.java:265)
        at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.build(SmallRyeOpenApiProcessor.java:217)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at io.quarkus.deployment.ExtensionLoader$1.execute(ExtensionLoader.java:768)
        at io.quarkus.builder.BuildContext.run(BuildContext.java:415)
        at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
        at java.base/java.lang.Thread.run(Thread.java:834)
        at org.jboss.threads.JBossThread.run(JBossThread.java:479)

The exception appears to come from FilteredIndexView line 70 because an array isn't going to have a '.' in the name.

Changing double[] to a List<Double> resolves the issue. However that doesn't seem like the correct solution.

Custom schema is ignored if @RequestBody is referenced

If I write this:

@POST
public void test(@RequestBody(content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = DifferentObject.class)), required = true) SomeObject body) { ... }

then everything is as expected:

    post:
      requestBody:
        $ref: '#/components/requestBodies/test'
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DifferentObject'

But if I use a ref instead:

@POST
public void test(@RequestBody(ref = "test") SomeObject body) { ... }
@OpenAPIDefinition(
    components = @Components(
        requestBodies = @RequestBody(name = "test", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = DifferentObject.class)), required = true)
    )
)

then the schema ref is incorrect:

    post:
      requestBody:
        $ref: '#/components/requestBodies/test'
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SomeObject'

Introduce a simpler version of ApiResponse annotation

OpenApi has an ApiResponse annotation which, via its nested Content, can provide the information about the JAX-RS Response entity class.

While this annotation covers well for a case where Response dynamically sets different entity types per the current response media type, it is too complex for a typical case of Response returning a known single entity type only, with @produces already typing a response media type.

One proposal is to have something like this:

@Produces("application/json")
@ApiResponseType(MyType.class)
@GET
public Response get() { return Response.ok(new MyType()).build(); }   

but other options should also be considered

Parameter with @Valid are not take account in schema

When a JSR303 annotation is used on the RequestBody of REST operation, the paths.{operation}.requestBody is not generated in the swagger documentation

This code was tested with OpenJDK Runtime Environment (build 1.8.0_161-b14) and Quarkus 0.14.0.

@Path("/fruits")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class FruitResource {

    private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));

    public FruitResource() {
        fruits.add(new Fruit("Apple", "Winter fruit"));
        fruits.add(new Fruit("Pineapple", "Tropical fruit"));
    }

    @GET
    public Set<Fruit> list() {
        return fruits;
    }

    @POST
    public Set<Fruit> add(@Valid /* JSR Bean validation*/ Fruit fruit) { 
        fruits.add(fruit);
        return fruits;
    }

    @DELETE
    public Set<Fruit> delete(Fruit fruit) { // no JSR validations
        fruits.remove(fruit);
        return fruits;
    }
}

This is the generated OpenAPI spec


openapi: 3.0.1
info:
  title: Generated API
  version: "1.0"
paths:
  /fruits:
    get:
      responses:
        200:
          description: OK
          content:
            application/json: {}
    post: 
      responses: #request body not generated for post
        200:
          description: OK
          content:
            application/json: {}
    delete:
      requestBody: #request body generated for delete
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Fruit'
      responses:
        200:
          description: OK
          content:
            application/json: {}
components:
  schemas:
    Fruit:
      properties:
        description:
          type: string
        name:
          type: string

I see it, it come from
OpenApiAnnotationScanner.processJaxRsMethod in the following block:

        // If the request body is null, figure it out from the parameters.  Only if the
        // method declares that it @Consumes data
        if (operation.getRequestBody() == null && currentConsumes != null) {
            Type requestBodyType = JandexUtil.getRequestBodyParameterClassType(method);
            if (requestBodyType != null) {
                Schema schema = typeToSchema(requestBodyType);
                if (schema != null) {
                    RequestBody requestBody = new RequestBodyImpl();
                    ModelUtil.setRequestBodySchema(requestBody, schema, currentConsumes);
                    operation.setRequestBody(requestBody);
                }
            }
        }

because JandexUtil.getRequestBodyParameterClassType return only parameter without annotation, but don't check if this is a not an @Parameter

Support extensions to JAX-RS

RESTEasy supports additions to JAX-RS, such as:

  • @FormParam, @QueryParam etc… that have an optional parameter name and uses the annotated param/field name
  • reactive return types such as RxJava Single or Flowable

Additionally, I know of applications that do not require Application classes to set up jax-rs resources.

It would be great to have extension points in smallrye-open-api to be able to hook into in order to support this behaviour. Swagger has such extension points that I was able to use for that.

Expand parameter scanning beyond resource method arguments

The list below is the full set of locations where we might find applicable parameter annotations to scan. The current implementation covers the first possibility.

Possible locations of @Parameter and JAX-RS parameter annotations

  1. Resource method arguments
  2. Resource method (@Parameter only)
  3. Resource class fields and bean property methods (setters)
  4. Fields and bean property methods of @BeanParam objects in locations 1 and 3.
  5. Support for @FormParam annotation by generating a wrapper requestBody/schema (relates to #123)

It's not clear in the MP OpenAPI spec whether @Parameter should be supported on resource class fields and bean properties. It seems reasonable to support them wherever JAX-RS parameter annotations can be found, but that may be debatable.

Change Java Date type format to DATE_TIME

java.util.Date is set to be a simple date without time:

TYPE_MAP.put(DotName.createSimple(Date.class.getName()), DATE_FORMAT);

Any (de)serializer that I know maps them to dates with time, never only the date part. Because of the definition of type date, Swagger-UI for example generates bad example values like "2019-07-01".

DATE_FORMAT should therefore be changed to DATE_TIME_FORMAT for both mentioned Java Date types.

OpenApiDataObjectScanner doesn't handle methods

There is already a relevant TODO in the source code, wondering if this is planned to be implemented at some point. I consider it to be a common use case to have to add OpenAPI schema annotation on a getter method (e.g. when dealing with interfaces) and swagger's scanner seems to support it as well.

Enable APIResponse auto-generation with annotations present

Methods returning a specific object type (with the exception of JAX-RS Response) do not need @APIResponse because of the auto detection, which is very handy.
Unfortunately you often cannot use that feature for some (most?) JAX-RS implementations. Because if you return null, RESTeasy for example returns 204 No Content and this cannot be declared without needing to also declare the @APIResponse for 200.

This is because the current logic does not auto generate anything if there is any explicitly defined @APIResponse annotation present:

if (operation.getResponses() == null || operation.getResponses().isEmpty()) {

There are multiple ways this could be changed:

  1. Auto generate default responses if the respective responseCode (200 for non-void methods, 201/204 for void methods) has not been explicitly defined. Although you then cannot disable them you can still override them.
  2. Auto generate default responses if an empty @APIResponse annotation is present.
  3. Introduce a new annotation or option to recognize that a methods return value is nullable. Then the auto generation can add a 204 response addtional to the 200.

PathItemImpl should consider multiple methods for same path

Currently a second method on the same path simply overrides a previously parsed operation. It should be allowed to have the same path multiple times for different content types. Instead of simply setting the new operation, it should be checked wether it is a different content type.

Consider the following (valid) OpenAPI specification with two different content types ("json" and "x-www-form-urlencoded"):

  /offices/create:
    post:
      summary: Creates a new office.
      operationId: createOffice
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOfficeCommand'
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - id
                - name
              properties:
                id:
                  type: string
                name:
                  type: string

This will be implemented in the same Java resource with two methods:

The first one allows a 'application/json' body:

@POST
@Path("/offices/create")
@Consumes({ MediaType.APPLICATION_JSON })
@Operation(operationId = "createOffice")

public void createOffice(@RequestBody(required = true, 
content = @Content(schema = @Schema(implementation = CreateOfficeCommand.class)))
final CreateOfficeCommand cmd) { ... }

The second one allows 'application/x-www-form-urlencoded' parameters:

@POST
@Path("/offices/create")
@Consumes("application/x-www-form-urlencoded")
@Operation(operationId = "createOffice")

public void createOffice(@FormParam("id") String id, @FormParam("name") String name) { ... }

Parsing the resource using the OpenApiAnnotationScanner currently the second "x-www-form-urlencoded" method definition overrides the first 'application/json' one.

Instead the second method for the same path ("/offices/create") should simply be added as another media type for the same operation.

Include type parameters in generated schema names

There was some discussion on generated schema names in #97. The current implementation in the SchemaRegistry uses a "name + 1" approach if a name collision occurs. The collision could occur in two scenarios - 1) if the same class name exists in multiple packages or 2) if the class name is a parameterized type.

This issue is addressing the second scenario. Consider the unit test ExpectationWithRefsTests#testComplexNestedGenericsWithRefs which is rooted on a field of type Fuzz<KustomPair<Fuzz<String, Date>, ?>, Double>. The current expected is as follows, note the sequential references to different Fuzz types.

{
  "components": {
    "schemas": {
      "KustomPair": {
        "required": [
          "bar",
          "foo"
        ],
        "type": "object",
        "properties": {
          "bar": {
            "type": "object"
          },
          "foo": {
            "$ref": "#/components/schemas/Fuzz"
          }
        }
      },
      "Fuzz": {
        "maxLength": 123456,
        "type": "object",
        "properties": {
          "qAgain": {
            "format": "date",
            "type": "string"
          },
          "qAgain3": {
            "format": "date",
            "type": "string"
          },
          "qValue": {
            "format": "date",
            "description": "Ah, Q, my favourite variable!",
            "type": "string"
          },
          "tAgain2": {
            "type": "string"
          },
          "tAgain4": {
            "type": "string"
          },
          "tValue": {
            "type": "string"
          }
        }
      },
      "Fuzz1": {
        "type": "object",
        "properties": {
          "qAgain": {
            "format": "double",
            "type": "number"
          },
          "qAgain3": {
            "format": "double",
            "type": "number"
          },
          "qValue": {
            "format": "double",
            "description": "Ah, Q, my favourite variable!",
            "type": "number"
          },
          "tAgain2": {
            "$ref": "#/components/schemas/KustomPair"
          },
          "tAgain4": {
            "$ref": "#/components/schemas/KustomPair"
          },
          "tValue": {
            "$ref": "#/components/schemas/KustomPair"
          }
        }
      }
    }
  }
}

Using type parameters would produce a more predictable result.

{
  "components" : {
    "schemas" : {
      "FuzzKustomPairDouble" : {
        "type" : "object",
        "properties" : {
          "qAgain" : {
            "format" : "double",
            "type" : "number"
          },
          "qAgain3" : {
            "format" : "double",
            "type" : "number"
          },
          "qValue" : {
            "format" : "double",
            "description" : "Ah, Q, my favourite variable!",
            "type" : "number"
          },
          "tAgain2" : {
            "$ref" : "#/components/schemas/KustomPairFuzzObject"
          },
          "tAgain4" : {
            "$ref" : "#/components/schemas/KustomPairFuzzObject"
          },
          "tValue" : {
            "$ref" : "#/components/schemas/KustomPairFuzzObject"
          }
        }
      },
      "KustomPairFuzzObject" : {
        "required" : [ "bar", "foo" ],
        "type" : "object",
        "properties" : {
          "bar" : {
            "type" : "object"
          },
          "foo" : {
            "$ref" : "#/components/schemas/FuzzStringDate"
          }
        }
      },
      "FuzzStringDate" : {
        "maxLength" : 123456,
        "type" : "object",
        "properties" : {
          "qAgain" : {
            "format" : "date",
            "type" : "string"
          },
          "qAgain3" : {
            "format" : "date",
            "type" : "string"
          },
          "qValue" : {
            "format" : "date",
            "description" : "Ah, Q, my favourite variable!",
            "type" : "string"
          },
          "tAgain2" : {
            "type" : "string"
          },
          "tAgain4" : {
            "type" : "string"
          },
          "tValue" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

This is probably a less common scenario in real world applications, but it would help with unit tests in this project :-)

JAX-RS parameters are all required by default

The following code produces below openapi file

@Path("test")
public class TestRS {

  @POST
  @Path("")
  public void test(@CookieParam ("cookieParam") String c, @HeaderParam("headerParam") String h, @QueryParam("queryParam") String q) {
  }
}
---
openapi: 3.0.1
info:
  title: Generated API
  version: "1.0"
paths:
  /rest/test:
    post:
      parameters:
      - name: cookieParam
        in: cookie
        required: true
        schema:
          type: string
      - name: headerParam
        in: header
        required: true
        schema:
          type: string
      - name: queryParam
        in: query
        required: true
        schema:
          type: string
      responses:
        201:
          description: Created

According to eclipse/microprofile-open-api#355 (comment) I'd expect only @PathParam of JAX-RS to be automatically set as required. The parameter types in the example above should have no required property or with a value of false.

I couldn't find the reason for the current behavior while jumping through the source code on GitHub, because at least here it looks fine:

Run junit TCK tests on non-8080 port

The tests start up a server on port 8080. Instead, it should start the server on a random port and then use that. Otherwise it's very possible to collide with something else running on the machine.

Merging enum schema with "YES" / "NO" literals gives "true" / "false" in resulting yaml.

Hi,

Leaving openapi.yaml in wepapp/META-INF/ with

...
components:
  schemas:
    "Insurance":
      title: "InsuranceStatus"
      type:  string
      enum:
        - YES
        - NO
        - NEVER
...

gives

...
components:
  schemas:
    Insurance:
      title: InsuranceStatus
      enum:
        - true
        - false
        - NEVER
      type:  string
...

THOUGH in examples are not affected and preserve "YES" / "NO" values for schemas' properties.

Investigate MicroProfile OpenAPI 2.0

Now that we have a first milestone release of MP-OpenAPI 2.0 (2.0-MR1), I think it would make sense to create a 2.0 branch in this repo to work on an implementation that is compatible with this version.

I have started to do it to validate some other stuff I am working on. This is interesting because it allows to find some issue/limitation in the API.

Can a 2.0 branch be created in this repo?

This would be similar to #44 (for 2.0 instead of 1.1)

OpenAPI document initialized message is unhelpful

When OpenAPI starts (in a quarkus project in this example), the log outputs a message like:

2019-04-03 00:32:12,172 INFO  [io.sma.ope.api.OpenApiDocument] (main) OpenAPI document initialized: io.smallrye.openapi.api.models.OpenAPIImpl@4593ff34

I erroneously thought that #29 (comment) would solve this, but the message is still visible. It should be removed.

Allow registering custom schema types

It should be possible to register your own schema types that will then be used during the annotation scanning process.

This would allow to provide schema information for external types. Sometimes you don't control types used in your components. This means you cannot add annotations for those types. In such cases it would be nice to use above feature.

Let's assume you want to provide your own schema definition for the UUID type.

components:
  schemas:
    UUID:
      type: string
      format: uuid
      pattern: ^[a-f0-9]{8}-?[a-f0-9]{4}-?[1-5][a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}$
      title: UUID
      description: Universally Unique Identifier
      example: de8681db-b4d6-4c47-a428-4b959c1c8e9a

Then you will use a reference everywhere for the UUID:

MyCommand:
  type: object
  required:
    - command-id
  properties:
    command-id:
      $ref: "#/components/schemas/UUID"

To achieve this you could do something like this in your Java code:

Type uuidType = Type.create(DotName.createSimple(UUID.class.getName()), Kind.CLASS);
Schema schema = new SchemaImpl();
schema.setType(Schema.SchemaType.STRING);
schema.setFormat("uuid");
schema.setPattern("^[a-f0-9]{8}-?[a-f0-9]{4}-?[1-5][a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}$");
schema.setTitle("UUID");
schema.setDescription("Universally Unique Identifier");
schema.setExample("de8681db-b4d6-4c47-a428-4b959c1c8e9a");
SchemaRegistry.currentInstance().register(uuidType, schema);

Unfortunately this does not work, because the OpenApiAnnotationScanner currently always creates a new SchemaRegistry instance in the scan() method.

There should be some kind of enhancement mechanism that allows setting your own types for the registry used by the scanner, that will then always be used. "Always" means that the definition will never be overwritten by the OpenApiAnnotationScanner.

An idea to implement this would be to add a kind of "registry" (interface) that returns schema definitions for fully qualified class names. The user can then create it's own implementation and register this class somewhere using a config mechanism.

Enhance code quality and JavaDoc

While digging into the code for creating my push, I found that there are many types and methods that do not have any JavaDoc comment. This makes it hard for a project newbie to understand what the code is actually doing. Also the code sometimes looks like it could be improved in regard to formatting. At least I wasn't able to find information about things like "line length", "tab policy" or "encoding".

I think it would therefore be a good idea to:

  • fix the JavaDoc
  • provide Eclipse formatting rules (could be used also in IntelliJ IDEA and Netbeans with a plugin)
  • format the code once using the new formatter
  • provide suggestions for Eclipse/IntelliJ IDEA/Netbeans on how to configure “Organize Imports”, “Members Sort Order” and "Save Actions" (see this article)
  • add the "jacoco-maven-plugin" to check code coverage
  • add the project to SonarCloud (free for OS projects)
  • publish the results of the build at SonarCloud (See cmd snippet below)

I know it is some work, but I think the project will benefit from this very quickly.

Example of args for pushing the build results to SonarCloud:

mvn clean deploy jacoco:report sonar:sonar -U -B -P sonatype-oss-release -s settings.xml -Dsonar.organization=xxx -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=${SONAR_LOGIN}"

Transient fields are included in Schema

Transient fields of Objects are not ignored for schema generation.

Example:
Test.java:

@XmlAccessorType(XmlAccessType.FIELD)
public class Test {
  private String serializable;
  private transient String notSerializable;
}

Generated openapi file:

components:
  schemas:
    Test:
      properties:
        serializable:
          type: string
        notSerializable:
          type: string

Investigate MicroProfile OpenAPI 1.1

With the release of microprofile-open-api planned mid December 2018, I have started to experiment with 1.1-SNAPSHOT of the API.

You can find the code in the 1.1 branch of my fork.
I am not sure it meet all your standard and requirements, but at least it compiles (and the tests are green).

If you are interested to have this somewhere in this repository, let me know.
Otherwise I can wait until version 1.1 of the API is released and then propose a PR against master

@BeanParam parameters are apparently ignored

We just had this report in the Quarkus bugtracker:

Describe the bug
The openapi does not support @BeanParam.
If the rest service method uses the @BeanParam this attribute is ignored in the generated openapi.yaml file.

Expected behavior
The openapi.yaml contains also the information from the @BeanParam parameter object.

Actual behavior
The @BeanParam is ignored and not generated in the openapi.yaml

To Reproduce

  1. Create rest method with a @BeanParam parameter
  2. Download openapi http://localhost:8080/openapi

Could you take a look?

Once it's fixed, we need to upgrade SmallRye OpenAPI in Quarkus: quarkusio/quarkus#2819

Reintroduce logging

It'd be great to be able to reintroduce (currently commented out) logging somehow that has been commented out. I've had to temporarily hack it back in for my development -- annoying subtle bug that I couldn't figure out from debugging alone -- and was clear once logging was back in.

Also, I think the logging will add a lot of value when support cases start arriving, etc.

What are people's thoughts about how best to do this?

@OpenAPIDefinition doesn't seem to work

I have a private playground application using Thorntail 2.2.0 (with smallrye-open-api:1.0.1 if I got that right). My entrypoint has these annotations:

@OpenAPIDefinition(info = @Info(title = "myFancyEndpoint", version = "0.9"))
@Path("fancy")
public class FancyEndpoint {

When I call localhost:8080/openapi, the returned yaml starts as follows:

---
openapi: 3.0.1
info:
  title: Generated API
  version: "1.0"
paths:
  ...

I would have expected title: myFancyEndpoint and version: "0.9". Did I miss something or is there something missing in the Smallrye implementation?

Order of tags is non-deterministic

I'm not sure why, but running the same project on different systems (OSes) yields different tag orders and therefore different endpoint group order in Swagger UI.

Example

Three classes, all in the same package:

@Tag(name = "A")
public class A {
  /* endpoints here */
}
@Tag(name = "B")
public class B {
  /* endpoints here */
}
@Tag(name = "C")
public class C {
  /* endpoints here */
}

Results

Windows system:

---
openapi: 3.0.1
info:
  title: test
  version: "1.0"
tags:
- name: A
- name: B
- name: C

Linux system:

---
openapi: 3.0.1
info:
  title: test
  version: "1.0"
tags:
- name: C
- name: A
- name: B

OpenAPISerializer: siblings value allongside $ref should not be serialized

With a spec containing some values defined near to the ref attribute, the output of OpenAPISerializer.serialize(openAPI, OpenAPISerializer.Format.JSON) serialize those member, producing an invalid spec.

Example :

createOpenAPI()
  .openapi("3.0.1")
  .info(
    createInfo()
      .title("Ping Specification")
      .version("1.0")
  )
  .addServer(
    createServer()
      .url("http://localhost:8000/")
  )
  .paths(
    createPaths()
      .addPathItem(
        "/ping", createPathItem()
          .GET(
            createOperation()
              .operationId("pingGet")
              .responses(
                createAPIResponses()
                  .addAPIResponse(
                    "200", createAPIResponse()
                      .description("OK")
                      .content(
                        createContent()
                          .addMediaType(
                            "application/json", createMediaType()
                              .schema(
                                createSchema()
                                  .ref("#/components/schemas/Hello")
                                  .type(Schema.SchemaType.OBJECT) // Wrong value because "$ref" is present
                                  .description("The hello type") // Wrong value because "$ref" is present
                              )
                          )
                      )
                  )
              )
          )
      )
  )
  .components(
    createComponents()
      .addSchema(
        "Hello", createSchema()
          .type(Schema.SchemaType.OBJECT)
          .addProperty(
            "timestamp", createSchema()
              .type(Schema.SchemaType.INTEGER)
              .description("Unix timestamp (generation time)")
              .format("int32")
          )
          .addProperty(
            "message", createSchema()
              .type(Schema.SchemaType.STRING)
          )
      )
  );

Produces:

{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "Ping Specification",
    "version" : "1.0"
  },
  "servers" : [ {
    "url" : "http://localhost:8000/"
  } ],
  "paths" : {
    "/ping" : {
      "get" : {
        "operationId" : "pingGet",
        "responses" : {
          "200" : {
            "description" : "OK",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Hello",
                  "description" : "The hello type",
                  "type" : "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "Hello" : {
        "type" : "object",
        "properties" : {
          "timestamp" : {
            "format" : "int32",
            "description" : "Unix timestamp (generation time)",
            "type" : "integer"
          },
          "message" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

In Swagger-Editor (online), I get this error:

Sibling values are not allowed alongside $refs

In KaiZen-Editor (plugin for Eclipse), I get this error:

Failed to match exactly one schema:

  • response:
    Failed to match exactly one schema:
    • schema:
      • object has properties "$ref" which are not allowed
    • reference:
      • object has properties "description", "type" which are not allowed
  • reference:
    • object has missing required properties "$ref"
    • object has properties "content", "description" which are not allowed

Expected would be:

{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "Ping Specification",
    "version" : "1.0"
  },
  "servers" : [ {
    "url" : "http://localhost:8000/"
  } ],
  "paths" : {
    "/ping" : {
      "get" : {
        "operationId" : "pingGet",
        "responses" : {
          "200" : {
            "description" : "OK",
            "content" : {
              "application/json" : {
                "schema" : {
                  "$ref" : "#/components/schemas/Hello"
                }
              }
            }
          }
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "Hello" : {
        "type" : "object",
        "properties" : {
          "timestamp" : {
            "format" : "int32",
            "description" : "Unix timestamp (generation time)",
            "type" : "integer"
          },
          "message" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

In my opinion, even if the model contains incorrect value (near to reference), the serializer should ignore them during JSON/YAML serialization.

What do you think?

Using @Schema disables enum value generation

Annotating an enum field with for example @Schema(required = true) stops auto generation of enum value info.
This unfotunately cannot be restored by specifying @Schema(implementation = MyEnum.class, required = true).
There should be a way. Best would be to not having to specify an implementation at all. I think the implementation should in fact be only overriden if you explicitly specify one. If not, the default generation should be used.
My proposal is to change Class<?> implementation() default Void.class; to Class<?> implementation() default Infer.class;, where Infer.class is just an internal control class. You will then have to specify Void.class yourself to disable auto generation.

Don't automatically sort object fields

I wondered why my OpenAPI file under Thorntail didn't look like I expected it to.
Classes under components.schemas always have sorted fields instead of their original order in the Java class.
I think it's because you are using ClassInfo from Jandex internally to get the field info. Unfortunately ClassInfo does automatic field sorting: https://github.com/wildfly/jandex/blob/61d1115e0a0f15dcfb2b0bbd082100f847963529/src/main/java/org/jboss/jandex/ClassInfo.java#L557

There seems to be no option to disable this behavior. Neither in this implementation, nor in Jandex ClassInfo.
I suggest not to alter the property order or at least make it optional (default: false).
Thanks :)

Don't create default response or parameter

When there is no @Parameter or @APIResponsefound on a JAXRS resource method, the OpenApiAnnotationScanner creates default values. I think this behavior is not correct.

  1. For the contract-first approach, the parameters and responses might already be described in the static file. At the moment of annotation scanning there is no info about that.
  2. The info might me omitted on purpose. I think the scanner shouldn't assume anything, just because the expected annotations are missing, even if it wasn't on purpose.

Any thoughts?

Token for Sonar Cloud is visible for the public in the build

There is a security problem with the build configuration: The private key for Sonar Cloud is visible in the build output. There should be some option in the build server to hide this information in the log output. And of course the password should be changed immediately.

mvn clean verify sonar:sonar -Dsonar.projectKey=smallrye_smallrye-open-api -Dsonar.projectName="SmallRye Open API" -Dsonar.organization=smallrye -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=977e5673bd92xxxxxxxxxx849e6f3c7500c4

Add schema reference of nested objects

Currently only top level classes are added to schemas section of the document and only these schemas are referenced. However if there is a nested class, it is always flattened out instead of creating a schema and referencing it.

For example I have the following 2 classes and a JAX-RS resource:

public class Foo {
	private String name;
	private Bar bar;

	//... getters/setters
}
public class Bar {
	private String note;

	//...getter/setter
}
@Path("foo")
public class FooResource {
	@GET
	public Foo getFoo() {
		return new Foo();
	}
}

Then the generated openapi documentation will look like:

paths:
  /foo:
    get:
      responses:
        200:
          description: OK
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/Foo'

components:
  schemas:
    Foo:
      properties:
        bar:
          type: object
          properties:
            note:
              type: string
        name:
          type: string

If class Bar is used many times, it is always flattened out everywhere instead of creating a schema for it and referencing it. So the desired format would be:

paths:
  /foo:
    get:
      responses:
        200:
          description: OK
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/Foo'

components:
  schemas:
    Foo:
      properties:
        bar:
          $ref: '#/components/schemas/Bar'
        name:
          type: string
    Bar:
      properties:
        note:
          type: string

I haven't found a way in the actual implementation to force out the Bar schema creation and referencing it where it is used.

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.