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:

  1. In Invoke one Microservices from another - PART 1: Container Images (this guide), we explain HOW-TO invoke one microservice from another;

  2. In Invoke one Microservices from another - PART 2: Kubernetes, as usual, we explain HOW-TO run the whole thing on Kubernetes

  3. 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;

Microservice B - the server

We start from the server because we need the server’s API for the client later on;

Maven Project

  • 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

  • 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:

microprofile-config.properties:
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:

GettingStartedEndpointClient.java:
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:

GettingStartedEndpoint.java:
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 browsersimple-microservice-clientsimple-microservice-server"

< Back to Guides