Micronaut Code Generator from Swagger/OpenAPI spec

Micronaut Code Generator from Swagger/OpenAPI spec

I'm really enjoying Micronaut. However, I do miss creating swagger/openapi specs first to document the requirements and then generating server-side stubs.

Although Swagger Codegen has support for a lot of server-side stubs (spring, jaxrs, resteasy, etc) it does not have support (as of this writing) generation of micronaut server-side stubs.

So, I thought I'd take a crack at it ;)

Though there are several tutorials out there in terms of creating your own codegen template, theory-wise, they all sound simple enough. Practice-wise, if you look at the other codegen templates, there seems to be more details that needs to be considered

So I created Swagger Codegen Micronaut Generator, by heavily copying from the SpringCodegen and its templates. And then I slowly modified it to use Micronaut instead. I chose SpringCodegen because Micronaut's coding style is very similar of that of Spring (the main difference is the secret sauce that Micronaut does during compile time).

I also simplified a lot in my Micornaut Swagger template (i.e. it assumes you are using jdk8+, it only creates interfaces as API stubs which by default throws UnsupportedOperationException, uses RxJava, etc)

The end result is a library which can be used along side swagger codegen to generate micronaut server-side stubs. Unfortunately though, integrating your own swagger template library with the swagger codegen is a bit m0re invovling. The great thing is that it works, and that you only have to do this when generating (which you can easily script as well) :)

# download swagger cli
curl -O https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.10/swagger-codegen-cli-3.0.10.jar

# download micronaut generator
curl -O https://dl.bintray.com/franz-see/maven-repo/ph/net/see/swagger-codegen-micronaut-generator/1.0.0/swagger-codegen-micronaut-generator-1.0.0.jar

# generate micronaut server-side stubs
java -cp swagger-codegen-micronaut-generator-1.0.0.jar:swagger-codegen-cli-3.0.10.jar \
  io.swagger.codegen.v3.cli.SwaggerCodegen \
  generate \
  -l ph.net.see.swaggercodegenmicronautgenerator.MicronautCodegen \
  -i /path/to/your/swagger.yaml \
  -o /where/you/want/the/project/to/be/generated

Here's a sample micronaut generated project using petstore's openapi 3.0 spec - https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml

As you can see above, the PetsApi is an interface with all the swagger/openapi annotation and description and details.

You can run this with sh mvnw clean install but you will have test failures because the PetsApi is an interface and it needs a concrete class to implement it.

14:46:12.124 [main] DEBUG io.micronaut.context.DefaultBeanContext - Finalized bean definitions candidates: [Definition: io.swagger.api.PetsApiControllerTest]
14:46:12.132 [main] DEBUG io.micronaut.context.DefaultBeanContext - Finding candidate beans for instance: [email protected]
14:46:12.134 [main] DEBUG io.micronaut.context.DefaultBeanContext - Finding candidate beans for type: interface io.swagger.api.PetsApi
14:46:12.134 [main] DEBUG io.micronaut.context.DefaultBeanContext - Resolved bean candidates [] for type: interface io.swagger.api.PetsApi
14:46:12.165 [main] DEBUG io.micronaut.context.DefaultBeanContext - Finding candidate beans for instance: [email protected]
14:46:12.170 [main] DEBUG io.micronaut.context.DefaultBeanContext - Finding candidate beans for instance: [email protected]
[ERROR] Tests run: 3, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 3,453.378 s <<< FAILURE! - in io.swagger.api.PetsApiControllerTest
[ERROR] showPetByIdTest  Time elapsed: 0.051 s  <<< ERROR!
io.micronaut.context.exceptions.DependencyInjectionException: 
Failed to inject value for field [api] of class: io.swagger.api.PetsApiControllerTest

Path Taken: PetsApiControllerTest.api
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [io.swagger.api.PetsApi] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).

[ERROR] createPetsTest  Time elapsed: 0.001 s  <<< ERROR!
io.micronaut.context.exceptions.DependencyInjectionException: 
Failed to inject value for field [api] of class: io.swagger.api.PetsApiControllerTest

Path Taken: PetsApiControllerTest.api
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [io.swagger.api.PetsApi] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).

[ERROR] listPetsTest  Time elapsed: 0 s  <<< ERROR!
io.micronaut.context.exceptions.DependencyInjectionException: 
Failed to inject value for field [api] of class: io.swagger.api.PetsApiControllerTest

Path Taken: PetsApiControllerTest.api
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [io.swagger.api.PetsApi] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).

[INFO] 
[INFO] Results:
[INFO] 
[ERROR] Errors: 
[ERROR]   PetsApiControllerTest.createPetsTest » DependencyInjection Failed to inject va...
[ERROR]   PetsApiControllerTest.listPetsTest » DependencyInjection Failed to inject valu...
[ERROR]   PetsApiControllerTest.showPetByIdTest » DependencyInjection Failed to inject v...
[INFO] 
[ERROR] Tests run: 3, Failures: 0, Errors: 3, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  57:57 min
[INFO] Finished at: 2019-07-23T14:47:33+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.0:test (default-test) on project swagger-micronaut: There are test failures.
[ERROR] 
[ERROR] Please refer to /private/tmp/testing2/project/target/surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date]-jvmRun[N].dump, [date].dumpstream and [date]-jvmRun[N].dumpstream.
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

To fix the build, you need to implement PetsApi. For example, create a PetsApiController which implements PetsApi.

package io.swagger.controller;

import io.micronaut.http.annotation.Controller;
import io.swagger.api.PetsApi;

@Controller
public class PetsApiController implements PetsApi {
}

Re-running sh mvnw clean install would now result into a build success

[WARNING] Tests run: 3, Failures: 0, Errors: 0, Skipped: 3, Time elapsed: 19.386 s - in io.swagger.api.PetsApiControllerTest
[INFO] 
[INFO] Results:
[INFO] 
[WARNING] Tests run: 3, Failures: 0, Errors: 0, Skipped: 3
[INFO] 
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ swagger-micronaut ---
[INFO] Building jar: /private/tmp/testing2/project/target/swagger-micronaut-1.0.0.jar
[INFO] 
...
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ swagger-micronaut ---
[INFO] Installing /private/tmp/testing2/project/target/swagger-micronaut-1.0.0.jar to /Users/franz/.m2/repository/io/swagger/swagger-micronaut/1.0.0/swagger-micronaut-1.0.0.jar
[INFO] Installing /private/tmp/testing2/project/dependency-reduced-pom.xml to /Users/franz/.m2/repository/io/swagger/swagger-micronaut/1.0.0/swagger-micronaut-1.0.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  43.770 s
[INFO] Finished at: 2019-07-23T14:50:56+08:00
[INFO] ------------------------------------------------------------------------

Note though that the tests are skipped until the actual api endpoints are implemented.

And with that, you now have a micronaut java application :) You can now start implementing those api endpoints :)

Appendix:

Swagger Codegen Micronaut Generator - https://github.com/franz-see/swagger-codegen-micronaut-generator

Petstore sample OpenAPI 3.0 spec - https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml

Swagger Codegen Cli Download URL : https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.10/swagger-codegen-cli-3.0.10.jar

Swagger Codegen Micronaut Download URL : https://dl.bintray.com/franz-see/maven-repo/ph/net/see/swagger-codegen-micronaut-generator/1.0.0/swagger-codegen-micronaut-generator-1.0.0.jar