Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WildFly mini series: REST Client #671

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 16 additions & 8 deletions guides/get-started-microservices-on-kubernetes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,22 @@ We will start building a link:https://docs.docker.com/[Docker Image, window="_bl

=== Guides in this series

* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part1[{simple-microservice-part1}]
* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part2[{simple-microservice-part2}]
* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part1[{simple-microservice-database-part1}]
* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part2[{simple-microservice-database-part2}]
* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part1[{simple-microservice-infinispan-part1}]
* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part2[{simple-microservice-infinispan-part2}]
* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part1[{simple-microservice-jms-part1}]
* link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part2[{simple-microservice-jms-part2}]
* **{simple-microservice-header}**
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part1[{simple-microservice-part1}]
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-part2[{simple-microservice-part2}]
* **{simple-microservice-database-header}**
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part1[{simple-microservice-database-part1}]
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-database-part2[{simple-microservice-database-part2}]
* **{simple-microservice-infinispan-header}**
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part1[{simple-microservice-infinispan-part1}]
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-infinispan-part2[{simple-microservice-infinispan-part2}]
* **{simple-microservice-jms-header}**
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part1[{simple-microservice-jms-part1}]
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-jms-part2[{simple-microservice-jms-part2}]
* **{simple-microservice-client-header}**
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part1[{simple-microservice-client-part1}]
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part2[{simple-microservice-client-part2}]
** link:/guides/get-started-microservices-on-kubernetes/simple-microservice-client-part3[{simple-microservice-client-part3}]
//* link:get-enterprise-ready[{get-enterprise-ready}]

[[references]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@
:jaxrs-example-project-groupId: org.wildfly.examples
:jaxrs-example-project-artifactId: jaxrs
:jaxrs-example-project-version: 11.0.0.Final-SNAPSHOT
:version-bootable-jar: 11.0.0.Beta1
:version-wildfly-galleon-pack: 32.0.0.Final
:version-wildfly: 35.0.0.Final
:version-wildfly-galleon-pack: 35.0.0.Final
:jakarta-jakartaee-api-version: 10.0.0
:version-junit-jupiter-api: 5.10.2
:version-arquillian-junit5-container: 1.8.0.Final
:version-org-wildfly-arquillian-wildfly-arquillian: 5.1.0.Beta1
:version-resteasy-client: 6.2.7.Final
:version-wildfly-cloud-galleon-pack: 7.0.0.Final
:version-wildfly-maven-plugin: 5.0.0.Final
:version-junit-jupiter-api: 5.11.3
:version-wildfly-cloud-galleon-pack: 7.0.2.Final
:version-wildfly-maven-plugin: 5.1.1.Final
:version-wildfly-maven-plugin-docs: 5.1
:my-jaxrs-app-docker-image-name: my-jaxrs-app
:my-jaxrs-app-db-docker-image-name: my-jaxrs-app-db
:my-jaxrs-app-infinispan-docker-image-name: my-jaxrs-app-infinispan
:quay-io-account-name: tborgato
:version-wildfly-datasources-galleon-pack: 8.0.0.Final
:version-wildfly-datasources-galleon-pack: 9.1.0.Final
:postgre-sql-user: postgres
:postgre-sql-password: admin
:postgre-sql-host: localhost
Expand Down Expand Up @@ -46,3 +44,19 @@
:artemis-console-port-name: artemis-console-port
:my-jms-app-docker-image-name: my-jms-app
:podman-network-name: demo-network
:simple-microservice-client: simple-microservice-client
:simple-microservice-server: simple-microservice-server
:simple-microservice-client-secured: simple-microservice-client-secured
:simple-microservice-server-secured: simple-microservice-server-secured
:keycloak-external: keycloak-external
:keycloak-internal: keycloak-internal
:keycloak-realm: keycloak-realm
:keycloak-data-import: keycloak-data-import
:keycloak-admin-user: admin
:keycloak-admin-pws: admin
:keycloak-user1: alice
:keycloak-user1-pws: 123
:keycloak-user2: bob
:keycloak-user2-pws: 123
:keycloak-role1: user
:keycloak-role2: admin
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
:simple-microservice-part1: WildFly Java Microservice - PART 1: Docker Image
:simple-microservice-header: WildFly Java Microservice
:simple-microservice-part1: WildFly Java Microservice - PART 1: Container Image
:simple-microservice-part2: WildFly Java Microservice - PART 2: Kubernetes
:simple-microservice-database-part1: Connecting to a DB - PART 1: Docker Image
:simple-microservice-database-header: Connecting to a DB
:simple-microservice-database-part1: Connecting to a DB - PART 1: Container Image
:simple-microservice-database-part2: Connecting to a DB - PART 2: Kubernetes
:simple-microservice-jms-part1: Using a Message Broker - PART 1: Docker Image
:simple-microservice-jms-header: Using a Message Broker
:simple-microservice-jms-part1: Using a Message Broker - PART 1: Container Image
:simple-microservice-jms-part2: Using a Message Broker - PART 2: Kubernetes
:simple-microservice-infinispan-part1: Using Infinispan remote cache - PART 1: Docker Image
:simple-microservice-infinispan-header: Using Infinispan remote cache
:simple-microservice-infinispan-part1: Using Infinispan remote cache - PART 1: Container Image
:simple-microservice-infinispan-part2: Using Infinispan remote cache - PART 2: Kubernetes
:simple-microservice-client-header: Invoke one Microservices from another
:simple-microservice-client-part1: Invoke one Microservices from another - PART 1: Container Images
:simple-microservice-client-part2: Invoke one Microservices from another - PART 2: Kubernetes
:simple-microservice-client-part3: Invoke one Microservices from another - PART 3: Propagate Authentication
:get-enterprise-ready: Get “Enterprise” ready
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
= {simple-microservice-client-part1}
:summary: Invoke one microservice from another
:includedir: ../_includes
include::{includedir}/_attributes.adoc[]
include::./_includes/_titles.adoc[]
include::_includes/_constants.adoc[]
// you can override any attributes eg to lengthen the
// time to complete the guide
:prerequisites-time: 10

In this guide, you will learn HOW-TO invoke one microservice from another;

[[prerequisites]]
== Prerequisites

To complete this guide, you need:

* Complete link:simple-microservice-part1[{simple-microservice-part1}]

== Introduction

This guide is the first in a series of three:

1. In link:simple-microservice-client-part1[{simple-microservice-client-part1}] (this guide), we explain HOW-TO invoke one microservice from another;
2. In link:simple-microservice-client-part2[{simple-microservice-client-part2}], as usual, we explain HOW-TO run the whole thing on Kubernetes
3. In link:simple-microservice-client-part3[{simple-microservice-client-part3}] 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 +++<u>two</u>+++ microservices:

* **Microservice A**: acting as **client**
* **Microservice B**: acting as **server**

Our invocation chain is then: "**Microservice A -> Microservice B**": when working with https://microprofile.io/[Microprofile], this is achieved by using the https://github.com/eclipse/microprofile-rest-client[microprofile-rest-client];

Specifically, **Microservice A** will use the https://github.com/eclipse/microprofile-rest-client[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 link:simple-microservice-part1[{simple-microservice-part1}] (complete code in {source-code-git-repository}/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 {source-code-git-repository}/simple-microservice into a new folder named *simple-microservice-server* and:

* remove folder *src/test*
* remove all test scope dependencies
Comment on lines +49 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this? Should the tests just be removed from the example if we remove them here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is about service ti service invocation and, unless we start both services in the same test, it would fail... perhaps we could leave the tests in the "server" service ...


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 link:simple-microservice-client-part3[{simple-microservice-client-part3}]

==== Build the application

[source,bash]
----
mvn clean package
----

=== Docker Image

==== Dockerfile

Since you copied {source-code-git-repository}/simple-microservice[simple-microservice], the Dockerfile from link:https://github.com/wildfly/wildfly-s2i/blob/main/examples/docker-build/Dockerfile[examples/docker-build/Dockerfile, window="_blank"] should already be at the root of your project;

==== Build the Docker Image

[source,bash,subs="normal"]
----
podman build -t {simple-microservice-server}:latest .
----

NOTE: You can use link:https://docs.wildfly.org/wildfly-maven-plugin/releases/{version-wildfly-maven-plugin-docs}/image-mojo.html[`wildfly-maven-plugin`, window="_blank"] to automate the image build

==== Run the Docker Image

First we create a network for our containers:

[source,bash,subs="normal"]
----
podman network create {podman-network-name}
----

Then we run our container using this network:

[source,bash,subs="normal"]
----
podman run --rm -p 8180:8080 -p 10090:9990 \
--network={podman-network-name} \
--name={simple-microservice-server} \
{simple-microservice-server}
----

== Microservice A - the client

=== Maven Project

Copy {source-code-git-repository}/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`:

[source,xml,subs="normal"]
----
<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`:

[source,xml,subs="normal"]
----
<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`:

[source,xml,subs="normal"]
----
<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:
[source,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 https://download.eclipse.org/microprofile/microprofile-config-3.0/microprofile-config-spec-3.0.html#default_configsources.env.mapping[env.mapping])

==== Java code

Add the following interface:

.GettingStartedEndpointClient.java:
[source,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:
Comment on lines +203 to +204
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a general question, should we be using the archetype instead and creating a new project if we need to keep deleting files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was to give the user the feeling that we were simply adapting the same project he's been working on in previous posts ... I figured that would result in a better understanding on the reader side of the modifications required for service to service invocation ...


.GettingStartedEndpoint.java:
[source,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

[source,bash]
----
mvn clean package
----

=== Docker Image

==== Dockerfile

Since you copied {source-code-git-repository}/simple-microservice[simple-microservice], the Dockerfile from link:https://github.com/wildfly/wildfly-s2i/blob/main/examples/docker-build/Dockerfile[examples/docker-build/Dockerfile, window="_blank"] 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:

[source,bash,subs="normal"]
----
podman build -t {simple-microservice-client}:latest .
----

NOTE: You can use link:https://docs.wildfly.org/wildfly-maven-plugin/releases/{version-wildfly-maven-plugin-docs}/image-mojo.html[`wildfly-maven-plugin`, window="_blank"] to automate the image build

==== Run the Docker Image

[source,bash,subs="normal"]
----
podman run --rm -p 8080:8080 -p 9990:9990 \
--network={podman-network-name} \
--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 **{podman-network-name}** network, using the *DNS* name **{simple-microservice-server}**

== Test

Open http://localhost:8080[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}**"

== What's next?

link:simple-microservice-client-part2[{simple-microservice-client-part2}]

[[references]]
== References

* https://microprofile.io/specifications/microprofile-rest-client[microprofile-rest-client]
* https://microprofile.io/specifications/microprofile-config[microprofile-config]
* Source code for this guide:
** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-client
** {source-code-git-repository}/simple-microservice-rest-client/simple-microservice-server


Loading