On a previous blog post, Triber Ivan Junckes Filho published an overview of the MicroProfile Rest Client (Rest Client) standard. In this tutorial, we are going to build on Ivan’s overview to show you, step by step, how you can develop and deploy this type-safe approach to consume an existing JAX-RS microservices with Apache TomEE 8 M1. If you have not read Ivan’s overview, it is suggested you do that first and then come back to this tutorial.

The toolset we are going to use for this tutorial includes Java 8, Apache TomEE 8 M1 and Maven 3.6. The technologies applied during the tutorial includes JAX-RS API and Arquillian for smooth and easy in-container testing.

Build and run the project

If you want to go straight to the action, you can execute the following commands to run the project, keep in mind that the rest client is created and executed only during the maven Test phase.

$ git clone https://github.com/tomitribe/tomee-mp-rest-client-starter-project.git
$ cd tomee-mp-rest-client-starter-project
$ mvn clean install tomee:run

If you want to run just the maven test phase:

$ mvn clean test

Feeling empowered? Awesome, but before going for more coffee, let’s review how this project is structured, the overall functionality of the microservice we are going to consume and finally the creation and usage of the MicroProfile Rest Client.

Project Structure


├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── org
    │           └── superbiz
    │               └── rest
    │                   ├── ApplicationConfig.java
    │                   ├── Movie.java
    │                   ├── MovieBean.java
    │                   └── MovieResource.java
    └── test
        ├── java
        │   └── org
        │       └── superbiz
        │           └── rest
        │               ├── MovieResourceClient.java
        │               └── MovieResourceTest.java
        └── resources
            ├── META-INF
            │   └── microprofile-config.properties
            └── arquillian.xml

The project structure follows the Maven standard conventions. For simplicity purposes we can divide the project structure, and the rest of this tutorial, into three sections:

  • pom.xml file defining the project name, package, and version along with the necessary java dependencies need it by the project.
  • src/main/../rest package containing all the classes need it by the project to expose a JAX-RS based Movie microservice with basic CRUD operations on a movie catalog.
  • src/test/ package containing an arquillian-base test to simplify how to configure and use the MicroProfile Rest Client.

About dependencies

We need to make sure our pom.xml file has both JavaEE 8 and MicroProfile dependencies. Notice that both dependencies have the scope provided, meaning that the artifact is automatically provided by TomEE and do not need to be packaged with your microservices.

<dependency>
	<groupId>org.apache.tomee</groupId>
	<artifactId>javaee-api</artifactId>
	<version>8.0</version>
	<scope>provided</scope>
</dependency>


<dependency>
	<groupId>org.eclipse.microprofile</groupId>
	<artifactId>microprofile</artifactId>
	<version>${version.microprofile}</version>
	<type>pom</type>
	<scope>provided</scope>
</dependency>

About the Movie microservice

The movie microservice is a JAX-RS endpoint with basic CRUD operations on a movie catalog. The following is a list of the available endpoints provided by the MovieResource.java

DELETE /api/catalog/movies/{id} ->  void deleteMovie(int)        
GET    /api/catalog/            ->  String status()              
GET    /api/catalog/movies      ->  List getListOfMovies()
GET    /api/catalog/movies/{id} ->  Movie getMovie(int)          
POST   /api/catalog/movies      ->  void addMovie(Movie)         
PUT    /api/catalog/movies      ->  void updateMovie(Movie)

How to build the Movie microservice is out of the scope of this tutorial but you can study the sample code on GitHub to learn how it works. If you want to know more about JAX-RS and arquillian you can check the blog post, Apache TomEE JAX-RS and Arquillian Starter Project.

Getting down to business with MicroProfile Rest Client

For developing the type-safe rest client, we need the following:

1) A client interface that you can use to make calls to the JAX-RS microservice.

The MovieResourceClient.java interface located in the src/test/../rest package is similar to the JAX-RS resource (MovieResource.java) but take notice of the usage of @RegisterRestClient and @Path("/test/api/catalog") annotations. The @RegisterRestClient declares the interface as a MicroProfile Rest Client Interface and the @Path defines the base URL for the microservice our client is going to consume.

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;

@RegisterRestClient
@Path("/test/api/catalog")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface MovieResourceClient {
    @GET
    String status();

    @POST
    @Path("/movies")
    void addMovie(Movie newMovie);

    @DELETE
    @Path("/movies/{id}")
    void deleteMovie(@PathParam("id") int id);

    @PUT
    @Path("/movies")
    void updateMovie(Movie updatedMovie);

    @GET
    @Path("/movies/{id}")
    Movie getMovie(@PathParam("id") int id);

    @GET
    @Path("/movies")
    List getListOfMovies();
}

2) A property file that declares the URL protocol and port of the movies microservice.

The microprofile-config.properties file located in src/test/resources/META-INF folder provides the URL protocol and port of the movies microservice. This property is going to be used along with the MovieResourceClient.java interface to build the absolute URL to consume the movie microservice.

org.superbiz.rest.MovieResourceClient/mp-rest/url=http://localhost:8080

This is where the fun of using the MicroProfile Rest Client begins. In the class MovieResourceTest.java the simplicity involved in the creation and usage of the client can really be appreciated. It’s clear and concise without an excessive amount of code or configuration.

At a high level, here’s how to build and use the client in the MovieResourceTest.java:
Inject the client by merely using the @Inject and @RestClient annotations in conjunction with the MovieResourceClient interface:

...
    //Injection point MP Rest Client
    @Inject
    @RestClient
    private MovieResourceClient mpClient;
...

From there you can start consuming the movie microservice with basic Java methods calls.

...
//POST
mpClient.addMovie(new Movie(1, "TomEE MicroProfile Adventures"));
mpClient.addMovie(new Movie(2, "Top 10 Tomee Configuraiton Tips"));

//GET
assertTrue(mpClient.getListOfMovies().size() == 2);
assertTrue(mpClient.getMovie(1).getName().equalsIgnoreCase("TomEE MicroProfile Adventures"));

//DELETE
mpClient.deleteMovie(1);
assertTrue(mpClient.getListOfMovies().size() == 1);
assertTrue(mpClient.getMovie(2).getName().equalsIgnoreCase("Top 10 Tomee Configuraiton Tips"));

//UPDATE
mpClient.updateMovie(new Movie(2, "Top 3 Tomee Configuraiton Tips"));
assertTrue(mpClient.getListOfMovies().size() == 1);
assertTrue(mpClient.getMovie(2).getName().equalsIgnoreCase("Top 3 Tomee Configuraiton Tips"));
...

This is the complete code of MovieResourceTest.java

import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;
import javax.inject.Inject;
import static org.junit.Assert.assertTrue;

@RunWith(Arquillian.class)
public class MovieResourceTest {
    
    //Arquillian deployment information
    @Deployment()
    public static WebArchive createDeployment() {
        final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "test.war")
                .addPackage(ApplicationConfig.class.getPackage())
                .addAsWebInfResource(new StringAsset(""), "beans.xml")
                .addAsResource("META-INF/microprofile-config.properties");
        return webArchive;
    }


    //Injection point MP Rest Client
    @Inject
    @RestClient
    private MovieResourceClient mpClient;

    @Test()
    public void testServerStatus() {
        assertTrue(mpClient.status().equalsIgnoreCase("ok"));
    }

    @Test
    public void tesMovieResource() {

        //POST
        mpClient.addMovie(new Movie(1, "TomEE MicroProfile Adventures"));
        mpClient.addMovie(new Movie(2, "Top 10 Tomee Configuraiton Tips"));

        //GET
        assertTrue(mpClient.getListOfMovies().size() == 2);
        assertTrue(mpClient.getMovie(1).getName().equalsIgnoreCase("TomEE MicroProfile Adventures"));

        //DELETE
        mpClient.deleteMovie(1);
        assertTrue(mpClient.getListOfMovies().size() == 1);
        assertTrue(mpClient.getMovie(2).getName().equalsIgnoreCase("Top 10 Tomee Configuraiton Tips"));

        //UPDATE
        mpClient.updateMovie(new Movie(2, "Top 3 Tomee Configuraiton Tips"));
        assertTrue(mpClient.getListOfMovies().size() == 1);
        assertTrue(mpClient.getMovie(2).getName().equalsIgnoreCase("Top 3 Tomee Configuraiton Tips"));
    }

}

Thank you for reading this tutorial, as you can see the MicroProfile Rest Client proposes a standardized approach to consume REST service via a Type-Safe approach in Java. You can learn more about it in https://microprofile.io/project/eclipse/microprofile-rest-client.
Let’s go now for more rewarding coffee and enjoy coding with Apache TomEE.

Cesar Hernandez

Cesar Hernandez

César has experience in the development of Enterprise Java Applications for public and private sectors. He has led implementations of Continuous Integration with Jmeter, SonarQube, Docker, Jenkins, Maven and JBehave. As a software architect he directed application server migrations with legacy systems to take advantage of modern technologies like JPA, CDI, JAX-WS and RESTful services.
CesarHgt

Leave a Reply