Invoke one Microservices from another - PART 1: Container Images
In this guide, you will learn HOW-TO invoke one microservice from another;
Prerequisites
To complete this guide, you need:
Introduction
This guide is the first in a series of three:
-
In Invoke one Microservices from another - PART 1: Container Images (this guide), we explain HOW-TO invoke one microservice from another;
-
In Invoke one Microservices from another - PART 2: Kubernetes, as usual, we explain HOW-TO run the whole thing on Kubernetes
-
In Invoke one Microservices from another - PART 3: Propagate Authentication we explain HOW-TO propagate user authentication and authorization data from the calling microservice to the invoked microservice; this is most useful in a scenario where you have a "chain" of microservices ("A → B → C → etc.") and you want the user’s authentication and authorization data to be propagated from one microservice to the next;
This Guide
In these guides, we work with a simple invocation chain composed by two microservices:
-
Microservice A: acting as client
-
Microservice B: acting as server
Our invocation chain is then: "Microservice A → Microservice B": when working with Microprofile, this is achieved by using the microprofile-rest-client;
Specifically, Microservice A will use the microprofile-rest-client to invoke the Jakarta REST service exposed by Microservice B;
For both services, we will start from the microservice we built in WildFly Java Microservice - PART 1: Container Image (complete code in https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice);
Microservice B - the server
We start from the server because we need the server’s API for the client later on;
Maven Project
Copy https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice into a new folder named simple-microservice-server and:
-
remove folder src/test
-
remove all test scope dependencies
Note
|
we remove tests because, since we are going to introduce service to service invocation, they wouldn’t be much useful anymore |
pom.xml
Update the artifactId
to <artifactId>simple-microservice-server</artifactId>
;
Note
|
Microservice B is basically unchanged, we will modify it in Invoke one Microservices from another - PART 3: Propagate Authentication |
Build the application
mvn clean package
Docker Image
Dockerfile
Since you copied simple-microservice, the Dockerfile from examples/docker-build/Dockerfile should already be at the root of your project;
Build the Docker Image
podman build -t simple-microservice-server:latest .
Note
|
You can use wildfly-maven-plugin to automate the image build
|
Run the Docker Image
First we create a network for our containers:
podman network create demo-network
Then we run our container using this network:
podman run --rm -p 8180:8080 -p 10090:9990 \
--network=demo-network \
--name=simple-microservice-server \
simple-microservice-server
Microservice A - the client
Maven Project
Copy https://github.com/wildfly-extras/guides/tree/main/get-started-microservices-on-kubernetes/simple-microservice into a new folder named simple-microservice-client and:
-
remove folder src/test
-
remove all test scope dependencies
Note
|
we remove tests because, since we are going to introduce service to service invocation, they wouldn’t be much useful anymore |
pom.xml
Update the artifactId to <artifactId>simple-microservice-client</artifactId>
;
Add the following to dependencyManagement
:
<dependency>
<groupId>org.wildfly.bom</groupId>
<artifactId>wildfly-expansion</artifactId>
<version>${version.wildfly.bom}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Add the following to dependencies
:
<dependency>
<groupId>org.eclipse.microprofile.rest.client</groupId>
<artifactId>microprofile-rest-client-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
<scope>provided</scope>
</dependency>
Add the following layers
in the wildfly-maven-plugin
:
<layer>microprofile-config</layer>
<layer>microprofile-rest-client</layer>
Later on, we will use:
-
microprofile-config to make the URL to Microservice B configurable
-
microprofile-rest-client to actually invoke Microservice B
microprofile-config.properties
As anticipated, we use microprofile-config to make the URL to Microservice B configurable;
Add file src/main/resources/META-INF/microprofile-config.properties
with the following content:
simple-microservice-server/mp-rest/uri=${simple-microservice-server-uri:http://127.0.0.1:8080}
simple-microservice-server/mp-rest/connectTimeout=3000
Note
|
simple-microservice-server-uri would pick up its value, whenever set, from the environment variable named SIMPLE_MICROSERVICE_SERVER_URI (see env.mapping)
|
Java code
Add the following interface:
package org.wildfly.examples;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@RegisterRestClient(configKey="simple-microservice-server")
@Path("/hello")
public interface GettingStartedEndpointClient {
@GET
@Path("/{name}")
@Produces(MediaType.TEXT_PLAIN)
Response sayHello(@PathParam("name") String name);
}
Note
|
this class is used to define the API to be invoked by the Rest Client; the actual URL where the remote service is
located, comes from the microprofile-config.properties file we just added;
|
Remove the src/main/java/org/wildfly/examples/GettingStartedService.java
file and replace the content of
src/main/java/org/wildfly/examples/GettingStartedEndpoint.java
with the following:
package org.wildfly.examples;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RestClient;
@Path("/")
public class GettingStartedEndpoint {
@Inject
@RestClient
private GettingStartedEndpointClient client;
@GET
@Path("/{name}")
@Produces(MediaType.TEXT_PLAIN)
public Response sayHello(final @PathParam("name") String name) {
return client.sayHello(name);
}
}
Note
|
as anticipated, we use microprofile-rest-client to actually invoke Microservice B |
Build the application
mvn clean package
Docker Image
Dockerfile
Since you copied simple-microservice, the Dockerfile from examples/docker-build/Dockerfile should already be at the root of your project;
Build the Docker Image
Build the Docker Image simple-microservice-client:latest
with the following command:
podman build -t simple-microservice-client:latest .
Note
|
You can use wildfly-maven-plugin to automate the image build
|
Run the Docker Image
podman run --rm -p 8080:8080 -p 9990:9990 \
--network=demo-network \
--env "SIMPLE_MICROSERVICE_SERVER_URI=http://simple-microservice-server:8080" \
--name=simple-microservice-client \
simple-microservice-client
Note
|
The simple-microservice-server container can be reached, inside the demo-network network, using the DNS name simple-microservice-server |
Test
Open http://localhost:8080 in your browser: this web page is served by the simple-microservice-client container;
Write something in the "Name" input box and then press "Say Hello": the response you’ll see will come from simple-microservice-server container!
The complete invocation chain is "web browser → simple-microservice-client → simple-microservice-server"
References
-
Source code for this guide: