Enabling the Asynchronous Server API in OpenAPI generated code for Jersey on demand
Asked Answered
C

1

6

We are using OpenAPI via gradle (i.e. openapi-generator-gradle-plugin) for generating Jersey resources. Generally speaking this works fine.

The generated methods look like this:

public Response getSomeFoo(@ApiParam(...) String someParam, ...) { ...

But we would also like to support methods that use the Asynchronous Server API.

In theory we could change all the generated synchronous methods to asynchronous ones, namely adapting the template files api.mustache and apiService.mustache where we replace the Response by void and adding the @Suspended final AsyncResponse asyncResponse as first parameter (plus adding the imports etc.).

But it does not make sense for us to convert all the requests from being processed synchronously to asynchronously.

So my question is: How can we achieve some kind of "switch" to indicate in the input file already what kind of implementation we want to generate (synchronously/asynchronously) for each method?

I was thinking of writing a new generator that reads in a e.g. a tag from the input spec file and puts this into a boolean variable which is evaluated in the template files. Is this feasible? Is there any similar issue solved already? Or do you have any other ideas for me?

Thanks!

Chon answered 4/9, 2019 at 11:49 Comment(0)
C
3

Found a solution myself now which is luckily quite handy: OpenAPI provides us with Extensions – one of which I used in order to solve the issue. I use my custom x-async-enabled extension in the spec JSON as follows:

"paths": {
   "/fubaz": {
     "get": {
       "summary": "My Fubaz resource",
       "operationId": "fubaz",
       "x-async-enabled": true,
 ...

And then I use this information in the template in order to conditionally generate a different signature for the respective methods (file api.mustache):

{{#operation}}
    public {{#vendorExtensions.x-async-enabled}}void{{/vendorExtensions.x-async-enabled}}{{^vendorExtensions.x-async-enabled}}Response{{/vendorExtensions.x-async-enabled}} {{nickname}}({{#vendorExtensions.x-async-enabled}}@Suspended final AsyncResponse asyncResponse, {{/vendorExtensions.x-async-enabled}}{{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}},{{/allParams}})
    throws Exception {
        {{#vendorExtensions.x-async-enabled}}
            delegate.{{nickname}}(asyncResponse, {{#allParams}}{{#isFormParam}}{{#isFile}}{{paramName}}InputStream, {{paramName}}Detail{{/isFile}}{{/isFormParam}}{{^isFile}}{{paramName}}{{/isFile}}{{^isFormParam}}{{#isFile}}{{paramName}}{{/isFile}}{{/isFormParam}}, {{/allParams}});
        {{/vendorExtensions.x-async-enabled}}
        {{^vendorExtensions.x-async-enabled}}
            return delegate.{{nickname}}({{#allParams}}{{#isFormParam}}{{#isFile}}{{paramName}}InputStream, {{paramName}}Detail{{/isFile}}{{/isFormParam}}{{^isFile}}{{paramName}}{{/isFile}}{{^isFormParam}}{{#isFile}}{{paramName}}{{/isFile}}{{/isFormParam}}, {{/allParams}});
        {{/vendorExtensions.x-async-enabled}}
    }
{{/operation}}

Of course I also had to adapt the imports and to do the basically same thing also in apiService.mustache. That did the trick for me and I can now just simply mark what I want to handle with the Asynchronous Server API.

Chon answered 4/9, 2019 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.