GitHub:
https://github.com/SafiBank/SaFiMono/tree/main/common/generated-client-publisher-plugin
https://github.com/SafiBank/SaFiMono/tree/main/common/generated-client-publisher-plugin-java
Overview
These two Gradle plugins are used for automating the generation of HTTP client APIs (for the services that expose such API). Being very similar, these plugins are documented together, to allow a compare-and-contrast approach.
Background
The generated-client-publisher-plugin
was initially developed as part of the effort to standardize the REST API versioning approach (more info can be found here: REST API versioning and client lib generation). The main problem with this plugin is that the generated clients were dependent on micronaut
, and tied to the specific micronaut
version of the service, which means that both the server (on which the client was built) and the consumer must be on the same version of micronaut. By extrapolation, this means that all microservices of the bank had to be on the same micronaut version.
To remove this high coupling, a new plugin was created (generated-client-publisher-plugin-java
), that would generate client APIs without depending on micronaut (exploration phase documented here: Using another generator for API clients), instead generating pure Java code. To make the transition smoother, these plugins are supposed to be used together, by each service. The result is that each service will be publishing two different client APIs, thus allowing their consumers to switch at their own pace. This PR will add the Java generator plugin to all services: https://github.com/SafiBank/SaFiMono/pull/7715
1. Micronaut-based generator
Gradle plugin that unifies and simplifies publishing of generated openapi clients to maven repository.
How it works
OpenapiClientPublisherPlugin performs following actions:
applies OpenAPI generator gradle plugin to generate code based on the OpenAPI yml file
registers a new task called
openApiGenerateAndBuild
to generate the client library jar fileapplies
MavenPublishPlugin
(for publishing in Maven format to Maven repository) andArtifactRegistryGradlePlugin
(for authentication against GCP artifact registry)creates
MavenPublication
(configuration of how Gradle should publish something in Maven format) that will be later configured by user of this plugin
Usage
On the client/user (microservice that wants to call rest api) side, following steps need to be done:
repositories for plugins need to be set in
settings.gradle.kts
- apart from implicit gradlePluginPortal, we need to add our maven repository by specifying this top level property:
pluginManagement { repositories { gradlePluginPortal() maven { url = uri("https://asia-southeast1-maven.pkg.dev/safi-repos/safi-maven") } } }
in
build.gradle.kts
, add the following plugin:
id("ph.safibank.common.generated.client.publisher") version "1.+"
in
settings.gradle.kts
,rootProject.name
must be properly set - it will be used in theartifactId
of the resulting artifactin
gradle.properties
, add:
group=ph.safibank.<servicename>
in
build.gradle.kts
, reference that property as:
group = project.properties["group"]!!
Outcome
The outcome of running gradle openApiGenerateAndBuild
will be the generated client artifact (with proper name/version) present in lib directory and ready to be published to maven repository:
maven repo is defined by OpenapiClientPublisherPlugin.mavenRepoUri ("https://asia-southeast1-maven.pkg.dev/safi-repos/safi-maven" at the time of writing)
groupId is defined by
$group.client
where $group is the project's groupartifactId in defined as
$name-api-client
where $name is the project's nameversion is defined in openapi.properties with the
micronaut.openapi.expand.api.version
property
2. Java-based generator
Gradle plugin that unifies and simplifies publishing of generated openapi clients to maven repository. Unlike generated-client-publisher-plugin
(based on the java-micronaut-client
generator type), is generates pure Java code (uses java
generator type) and does not depend on micronaut.
How it works
OpenapiClientPublisherPlugin performs following actions:
applies OpenApi generator gradle plugin to generate code based on the OpenApi yml file
registers a new task called 'openApiGenerateAndBuildJava' to generate the client library jar file
applies MavenPublishPlugin (for publishing in Maven format to Maven repository) and ArtifactRegistryGradlePlugin (for authentication against GCP artifact registry)
creates MavenPublication (configuration of how Gradle should publish something in Maven format) that will be later configured by user of this plugin
Usage of Plugin
add the following plugin in
build.gradle.kts
:
id("ph.safibank.common.generated.client.publisher.java") version "1.+"
for now, it is expected that this plugin will be used alongside the micronaut generator - keep this line in
build.gradle.kts
:
id("ph.safibank.common.generated.client.publisher") version "1.+"
this will ensure that both client APIs are generated (
java-micronaut-client
and purejava
versions)for the motivation on using these plugins in the first place - see README.md for
generated-client-publisher-plugin
Outcome
The outcome of running gradle openApiGenerateAndBuildJava
will be generated client artifact (with proper name/version) present in lib directory and ready to be published to maven repository:
maven repo is defined by OpenapiClientPublisherPlugin.mavenRepoUri ("https://asia-southeast1-maven.pkg.dev/safi-repos/safi-maven" at the time of writing)
groupId is defined by
$group.client
where $group is the project's groupartifactId in defined as
$name-api-client-java
where $name is the project's name
Usage of Client
this version of the generated client cannot access
application.yml
, so it reads url directly from environment. So everything that needs to be done is to have defined environment variableSAFI_<service_name>_URL
.a wrapper with the name
<service_name>Wrapper
is also generated, which initializes the client with the service URLin the consuming service, the recommended way of usage is to create a client/Clients.kt file, containing subclasses of all the generated clients, each marked as
@Singleton
:
package ph.safibank.infobipemailgateway.client import jakarta.inject.Singleton import ph.safibank.accountmanager.java.client.AccountManagerWrapper @Singleton class AccountManagerClient(): AccountManagerWrapper() @Singleton class CustomerManagerClient(): CustomerManagerWrapper() [...]
now, these clients are injectable throughout the owning service
these clients are not drop-in replacements of the
java-micronaut-client
ones - expect that minor changes are needed, due to different APIs of the generated classese.g.:
java-micronaut-client
generates constructors with parameters vs.java
uses builders