A Simple Helidon MicroProfile Microservice Demonstrating Many of the Commonly used JAX-RS APIs

Helidon is a collection of Java libraries for writing microservices that run on a fast web core powered by Netty. In this post I am sharing a simple Helidon MicroProfile based microservice example application that illustrates all commonly used JAX-RS APIs.

Please be warned that this example is just meant for exercising all common JAX-RS APIs on a simple Helidon microservice(not really production quality code/implementation). You can use this example as a base project for quickly trying out some use cases or starting some POCs around Helidon MP. Please refer to official documentation to learn more about each JAX-RS APIs/features discussed in this post(links to official docs are given at appropriate places)

If you are new to JAX-RS, please take a step back and read the following Jersey tutorial (Jersey implements JAX-RS spec and also offers more useful features as extensions). To learn more about Helidon, read the official doc.

The following diagram may help you to understand high level building blocks for this example:

To run this microservice example, do the following:

1.Set up a database for use in our example. You are free to choose database of your choice. This example uses a a very lightweight and simple database — SQLite. To learn more about SQLite, visit the following link: https://www.sqlite.org/index.html. SQLite is included in macOS and Mac OS X by default.

2.Define a Departments table in SQLite database.

CREATE TABLE departments
( department_id NUMBER(4)
, department_name VARCHAR2(30)
CONSTRAINT dept_name_nn NOT NULL
, manager_id NUMBER(6)
, location_id NUMBER(4)
) ;
CREATE UNIQUE INDEX dept_id_pk
ON departments (department_id) ;

3.Clone the git repository

git clone https://github.com/jobinesh/micro-java-samples.git

4. Navigate to micro-java-samples/helidon/hr-service-mp

cd micro-java-samples/helidon/hr-service-mp

5. Make sure you have installed all tools mentioned under Prerequisites in the following doc: https://github.com/jobinesh/micro-java-samples/blob/master/helidon/hr-service-mp/README.md

6. Once all set, package the microservice

mvn package

7. Run the service. You can access desired REST API now e.g: http://localhost:8080/departments. Jump to the section “Tips for Testing the RESTful Web APIs” of this post to learn more on APIs exposed in this example

java -jar target/hr-service-mp.jar

What is offered in this example?

Here is quick overview of some of the JAX-RS features exercised in this example along with fully qualified name of implementation classes.

Configuration of PersistenceManager used in JPA entities: A typical REST API implementation need a way to read and write data from datastore/database. This example uses JPA entity to deal with database ;)

The class com.jobinesh.helidon.mp.demo.hr.entity.PersistenceManager used in this example holds config entries required for establishing a connection with database. If you use different DB, make sure you are changing the connection config entries in property map present in PersistenceManager class. Please note that this example uses HikariCP JDBC connection pool: https://brettwooldridge.github.io/HikariCP/ . To know how to configure datasource to use HikariCP, take a look at the method createDataSource() in PersistenceManager class.

Adding JPA Entity mapping to appropriate database Table: Once connection to DB is established, you can try adding model entities which maps to database tables as required. See com.jobinesh.helidon.mp.demo.hr.entity.Department to learn how a JPA entity class is mapped to DEPARTMENTS table. You can follow same approach for building JPA entities mapping to databases tables of your choice.

Exposing department resource as REST endpoint: Now you can start exposing appropriate methods from service implementation class as REST end point. If you are new to this topics, please read this tutorial https://jersey.github.io/documentation/2.27/getting-started.html#new-from-archetype .

See com.jobinesh.helidon.mp.demo.hr.services.DepartmentResource to learn how to expose DepartmentResource methods as REST endpoint. The DepartmentResource class that we use in this exposes CRUD operations on department resource.

JAX-RS let you to build async REST APIs as well. The class com.jobinesh.helidon.mp.demo.hr.services.DepartmentAsynchResource demonstrates how to build asynch JAX-RS rest service. To learn more about async REST APIs, see the following doc https://jersey.github.io/documentation/2.27/async.html#d0e9895

Caching of REST resource let client to cache resources as appropriate. The class com.jobinesh.helidon.mp.demo.hr.services.DepartmentCachedResource illustrates how to enable caching of REST resources using JAX-RS APIs. Although JAX-RS APIs used in this example are self explanatory, the following doc may help you to understand them better: https://javaee.github.io/tutorial/jaxrs.html#GIEPU

Please note that above mentioned three representation of department resource are only meant for demonstrating various offerings of JAX-RS via three simple dedicated implementations. In real life you do not need to have multiple implementation classes for a single resource, unless there is a real need.

Configuring Request and Response Filters: JAX-RS lets you to configure filters which can modify inbound and outbound requests and responses including headers, entities and other request/response parameters. Read the following doc if you are new to JAX-RS Filters: https://jersey.github.io/documentation/latest/filters-and-interceptors.html . The class com.jobinesh.helidon.mp.demo.hr.ext.filter.ContainerRequestLoggerFilter if a filter used in this example to selectively enable logging of requests. This is done via dynamic binding feature offered in JAX-RS. In this example, runtime dynamically binds ContainerRequestLoggerFilter to a request if the resolved target methods is annotated with @RequestLogger. The dynamic binding of ContainerRequestLoggerFilter is achieved via the following class: com.jobinesh.helidon.mp.demo.hr.ext.dynamic.DynamicFeatureRegister. To learn more about dynamic binding, read the following doc: https://jersey.github.io/documentation/latest/filters-and-interceptors.html#d0e9748

You can have filter for REST response as well. The response filter class com.jobinesh.helidon.mp.demo.hr.ext.filter.ContainerResponseCORSFilter enables cross domain access by writing appropriate header data to the response content.

Usage of Request and Response Interceptors : JAX-RS Interceptors are used for modification of entity input and output streams. The following doc may help you to learn more about this topic: https://jersey.github.io/documentation/latest/filters-and-interceptors.html#d0e9505 .

This example uses com.jobinesh.helidon.mp.demo.hr.ext.interceptor.CSVMessageBodyReader interceptor class to read request payload represented in application/csv format. This feature demonstrates creation of multiple department resources represented in CSV format in one go(creation fo resources in batches).

The class com.jobinesh.helidon.mp.demo.hr.ext.interceptor.CSVMessageBodyWriter demonstrates how to write response in application/csv format.

Configuring the RESTful Web API Application: JAX-RS provides a deployment agnostic abstract class ‘Application’ for declaring root resource and provider classes. The class com.jobinesh.helidon.mp.demo.hr.main.HRServiceApplication configures all resources used in this example. The following doc may help you to learn more on this topic: https://jersey.github.io/documentation/latest/deployment.html#environmenmt.appmodel

Tips for Testing the RESTful Web APIs

You can test the APIs using tools of your choice :) One of the popular tool is postman. The following screen shot of postman may give you some hints on using this tool to test the REST APIs:

Here are some useful tips for quickly trying out some of the JAX-RS features present in this example:

This example exposes three REST end points as shown here:

1. http://localhost:8080/departments : This endpoint exposes all basic CRUD operations and some advanced features , which is discussed below
2. http://localhost:8080/asynch/departments : This endpoint demonstrates asynchronous calls
3. http://localhost:8080/cached/departments : This endpoint demonstrates caching of resources

The following example illustrates the basic CRUD operations on department resource:

REST Resource Class: com.jobinesh.helidon.mp.demo.hr.services.DepartmentResource
You can use the following input to create a department 
*  URL : http://localhost:8080/departments/
* HTTP Method : POST
* Content-Type: application/json
* Request Body(Payload) :
{
"departmentId": 10,
"departmentName": "Admin",
"locationId": 1700,
"managerId": 200
}
You can also try GET/PUT/DELETE with above end point. For instance the following request reads department with id=10
*  URL : http://localhost:8080/departments/10
* HTTP Method : GET
* Content-Type: application/json

The following example shows how to enable a REST API that reads input the sent in CSV format . This example uses CSV format to wrap multiple departments data in single request. This feature is used here for batch creation or update of departments.

REST Resource Class: com.jobinesh.helidon.mp.demo.hr.services.DepartmentResource
You can use the following input to test the REST API
*  URL : http://localhost:8080/departments/batch
* HTTP Method : POST
* Content-Type: application/csv
* Request Body(Payload) :
departmentId,departmentName,locationId,managerId
10,”HR”,1700,101
20,”IT”,1500,201
30,”Revenue”,1500,201

The following example shows how to retrieve department resources in csv format:

REST Resource Class: com.jobinesh.helidon.mp.demo.hr.services.DepartmentResource
You can use the following input to test the REST API

* URL : http://localhost:8080/departments/batch
* HTTP Method : GET
* Content-Type: application/csv

The following example showcases how to enable caching of resources via JAX-RS APIs( Cache-Control & ETag):

REST Resource Class: com.jobinesh.helidon.mp.demo.hr.services.DepartmentCachedResource
You can use the following input to test the REST API
Testing Cache-Control Offerings:
* URL: http://localhost:8080/cache/departments/10
* HTTP Method: GET
* Content-Type: application/json
* Set request Header: if-modified-since:<Use value of Last-Modified header value from last response for same resource>

Testing ETag Offerings:
* URL: http://localhost:8080/cache/departments/etag/10
* HTTP Method: GET
* Content-Type: application/json
* Set request Header: If-None-Match :<ETag from last response for same resource>

You can also use Java Client to test the above APIs. Refer to hr-service-mp-client project to learn how to use JAX-RS client APIs for exercising the REST APIs exposed by the hr-service-mp microservice example that we discussed in this post.

Let me stop here. In fact, there are some more JAX-RS features exercised in this example such as javax.ws.rs.ext.ExceptionMapper, javax.ws.rs.FormParam, javax.ws.rs.MatrixParam, javax.ws.rs.BeanParam and the list go on... You can explore them later at your leisure by cloning the git repository mentioned at the beginning of this post. Have fun :)

The views expressed on this post are my own and do not necessarily reflect the views of my employer.