Reference-documents for initial reading: https://www.visual-paradigm.com/guide/development/code-first-vs-design-first/ https://www.polak.ro/2021/04/02/api-first-and-code-generation-done-right.html
This document explains how to use the openapi-generator to come-up with the underlying Controller/DTO codes based on an API contract (OpenAPI/Swagger specifications).
Coming up with the API contract first, allows for a readable document that both the business-stakeholders and developers can easily understand. This also allows for a cleaner way of developing the controller components, leaving it out to the generator to build components containing the annotations on controller and DTOs which developers would otherwise code manually. This way, developers will simply focus on the business-logic part of the controller, by overriding the generated controller-components containing the intended core-service calls.
How Tos
1. Build a version of OpenAPI specs (contract) based on requirements (e.g. euronet-gateway-api-1.0.0.yaml)
openapi: 3.0.1 info: title: Card Transaction API version: 1.0.0 paths: /transaction/card-outbound-auth: post: tags: - Transaction summary: Initiates new transaction to reserve fund. description: Returns information about initialized transaction status. operationId: initiateCardTransactionOutboundAuth parameters: - name: idempotency-key in: header required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/OutboundAuthTransactionRequestDto" responses: "201": description: Transaction was created internally and is being processed by the payment gateway content: application/json: schema: $ref: "#/components/schemas/CardTransactionOutboundAuthResponseDto" "400": description: Requested payload contains invalid properties "500": description: Internal Server Error components: schemas: OutboundAuthTransactionRequestDto: allOf: - $ref: "#/components/schemas/CommonRequestDto" - $ref: "#/components/schemas/ExtendedRequestDto" #... removed other configuration
2. OpenAPI generator plugin is added to the domain-service buil containing:
a. plugin-definition with common config options (which can also be further extracted a common plugin)
b. openApiGenerate task (adding it as a dependency for the compile-task
c. reference to the generated-source directory
plugins { id("org.openapi.generator") version "6.2.0" } openApiGenerate { generatorName.set("java-micronaut-server") inputSpec.set("$projectDir/src/main/resources/openapi/euronet-gateway-api-1.0.0.yaml".toString()) outputDir.set("$buildDir/generated/openapi".toString()) templateDir.set("$projectDir/src/main/resources/openapi/templates".toString()) apiPackage.set("ph.safibank.euronetgateway.api") modelPackage.set("ph.safibank.euronetgateway.model") generateApiDocumentation.set(false) generateApiTests.set(false) generateModelTests.set(false) configOptions.set( mapOf( "generateControllerAsAbstract" to "true", "templateDir" to "$projectDir/src/main/resources/openapi/templates", "oas3" to "true", "build" to "gradle", "micronautVersion" to "3.7.0", "dateLibrary" to "java8", "reactive" to "false", "delegatePattern" to "true", "interfaceOnly" to "true", "skipDefaultInterface" to "false", "serializationLibrary" to "jackson", "openApiNullable" to "false", "micronautVersion" to "${project.properties["micronautVersion"]}" ) ) } tasks { compileKotlin { kotlinOptions { jvmTarget = "17" } dependsOn("openApiGenerate") } } sourceSets.main.get().java { srcDir("$buildDir/generated/openapi/src/main/java") }
3. Override the generated Controller component and add the required core-service logic
Generated components:
Override the generated controller-component:
Attachments:
Screen Shot 2022-10-10 at 11.56.30 AM.png (image/png)
Screen Shot 2022-10-10 at 11.56.48 AM.png (image/png)