Tutorial
This tutorial describes how to build a Helidon MicroProfile (MP) application from scratch including JSON REST endpoints, metrics, health check, and configuration.
What You Need
For this 30 minute tutorial, you will need the following:
| Requirement | Description |
|---|---|
| Java 21 (Open JDK 21) | Helidon requires Java 21+ (25+ recommended). |
| Maven 3.8+ | Helidon requires Maven 3.8+. |
| Docker 18.09+ | If you want to build and run Docker containers. |
| Kubectl 1.16.5+ | If you want to deploy to Kubernetes, you need kubectl and a Kubernetes cluster. |
| curl | (Optional) for testing |
Verify Prerequisites:
java -version
mvn --version
docker --version
kubectl version
Setting JAVA_HOME:
# On Mac
export JAVA_HOME=`/usr/libexec/java_home -v 21`
# On Linux
# Use the appropriate path to your JDK
export JAVA_HOME=/usr/lib/jvm/jdk-21
Create the Maven Project
This tutorial demonstrates how to create the application from scratch, without using the Maven archetypes as a quickstart.
Create a new empty directory for the project (for example,
helidon-mp-tutorial). Change into this directory.
Create a new Maven POM file (called pom.xml) and add the following content:
The POM file contains the basic project information and configurations needed to get started.
With this pom.xml, the application can be built successfully with Maven:
mvn clean package
This will create a JAR file in the target directory.
JAR will be empty - no content was marked for inclusion!
can be ignored for now because there is no actual content in the application
yet.Start Implementing the MicroProfile Application
The actual application logic can be created now. Create a directory for your source code, and then create directories for the package hierarchy:
Create directories for source code:
mkdir -p src/main/java/io/helidon/examples
The application will be a simple REST service that will return a greeting to the caller. The first iteration of the application will contain a resource class and a Main class which will be used to start up the Helidon server and the application.
mainClass property to
io.helidon.microprofile.cdi.Main and it will use Helidon’s default main
class.The GreetResource is defined in the GreetResource.java class as shown below:
A main class is also required to start up the server and run the application. If you don’t use Helidon’s built-in main class you can define your own:
In this class, a main method is defined which starts the Helidon MP server and
prints out a message with the listen address.
Helidon MP applications also require a beans.xml resource file to tell
Helidon to use the annotations discussed above to discover Java beans in the
application.
Create a beans.xml in the src/main/resources/META-INF directory with the
following content:
Build the Application
Helidon MP applications are packaged into a JAR file and the dependencies are
copied into a libs directory.
Build the Application:
mvn package
This will build the application jar and save all runtime dependencies in the
target/libs directory. This means you can easily start the application by
running the application jar file:
Run the application:
java -jar target/helidon-mp-tutorial.jar
At this stage, the application is a very simple "Hello World" greeting service. It supports a single GET request for generating a greeting message. The response is encoded using JSON. For example:
Try the Application:
curl -X GET http://localhost:7001/greet
{"message":"Hello World!"}
In the output you can see the JSON output from the getDefaultMessage() method
that was discussed earlier. The server has used a default port 7001. The
application can be stopped cleanly by pressing Ctrl+C.
Configuration
Helidon MP applications can use the META-INF/microprofile-config.properties
file to specify configuration data. This file (resource) is read by default if
it is present on the classpath. Create this file in
src/main/resources/META-INF with the following content:
Initial microprofile-config.properties:
# MicroProfile server properties
server.port=8080
server.host=0.0.0.0
Rebuild the application and run it again. Notice that it now uses port 8080 as specified in the configuration file.
In addition to predefined server properties, application-specific configuration
information can be added to this file. Add the app.greeting property to the
file as shown below. This property will be used to set the content of greeting
message.
Updated META-INF/microprofile-config.properties:
# MicroProfile server properties
server.port=8080
server.host=0.0.0.0
# Application properties
app.greeting=Hello
Add a new "provider" class to read this property and make it available to the
application. The class will be called GreetingProvider.java and have the
following content:
The GreetResource must be updated to use this value instead of the hard coded
response. Make the following updates to that class:
Updated GreetResource class:
Rebuild and run the application. Notice that it now uses the greeting from the configuration file. Change the configuration file and restart the application, notice that it uses the changed value.
Extending the Application
In this section, the application will be extended to add a PUT resource method which will allow users to update the greeting and a second GET resource method which will accept a parameter.
Here are the two new methods to add to GreetResource.java:
New methods for GreetResource.java:
Rebuild and run the application. Test the new services using curl commands similar to those shown below:
Testing the new services:
curl -X GET http://localhost:8080/greet
{"message":"Hello World!"}
curl -X GET http://localhost:8080/greet/Joe
{"message":"Hello Joe!"}
curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting
curl -X GET http://localhost:8080/greet/Jose
{"message":"Hola Jose!"}
Helidon MP provides many other features which can be added to the application.
Logging
The application logging can be customized. The default logging provider is
java.util.logging, however it is possible to use other providers. In this
tutorial the default provider is used.
Create a logging.properties file in src/main/resources with the following
content:
Example logging.properties file:
The Helidon MicroProfile server will detect the new logging.properties file
and configure the LogManager for you.
Rebuild and run the application and notice the new logging format takes effect.
Log output:
Aug 22, 2019 11:10:11 AM io.helidon.webserver.LoomWebServer lambda$start$8
INFO: Channel '@default' started: [id: 0xd0afba31, L:/0:0:0:0:0:0:0:0:8080]
Aug 22, 2019 11:10:11 AM io.helidon.microprofile.server.ServerImpl lambda$start$10
INFO: Server started on http://localhost:8080 (and all other host addresses) in 182 milliseconds.
http://localhost:8080/greet
2019.08.22 11:24:42 INFO io.helidon.webserver.LoomServer Thread[main,5,main]: Version: 1.2.0
2019.08.22 11:24:42 INFO io.helidon.webserver.LoomServer Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default' started: [id: 0x8f652dfe, L:/0:0:0:0:0:0:0:0:8080]
2019.08.22 11:24:42 INFO io.helidon.microprofile.server.ServerImpl Thread[nioEventLoopGroup-2-1,10,main]: Server started on http://localhost:8080 (and all other host addresses) in 237 milliseconds.
http://localhost:8080/greet
Metrics
Helidon provides built-in support for metrics endpoints.
Metrics in Prometheus Format:
curl -s -X GET http://localhost:8080/metrics
Metrics in JSON Format:
curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
It is possible to disable metrics by adding properties to the
microprofile-config.properties file, for example:
Disable a metric:
metrics.base.classloader.currentLoadedClass.count.enabled=false
Call the metrics endpoint before adding this change to confirm that the metric is included, then add the property to disable the metric, rebuild and restart the application and check again:
Checking metrics before and after disabling the metric:
curl -s http://localhost:8080/metrics | grep classloader_current
# TYPE base:classloader_current_loaded_class_count counter
# HELP base:classloader_current_loaded_class_count Displays the number of classes that are currently loaded in the Java virtual machine.
base:classloader_current_loaded_class_count 7936
curl -s http://localhost:8080/metrics | grep classloader_current
# (no output)
Helidon also support custom metrics. To add a new metric, annotate the JAX-RS resource with one of the metric annotations as shown in the example below:
Updated GreetResource.java with custom metrics:
Rebuild and run the application. Make some calls to the endpoint (http://localhost:8080/greet) so there will be some data to report. Then obtain the application metrics as follows:
Checking the application metrics:
curl -H "Accept: application/json" http://localhost:8080/metrics/application
{
"io.helidon.examples.GreetResource.getDefaultMessage": {
"count": 2,
"meanRate": 0.036565171873527716,
"oneMinRate": 0.015991117074135343,
"fiveMinRate": 0.0033057092356765017,
"fifteenMinRate": 0.0011080303990206543,
"min": 78658,
"max": 1614077,
"mean": 811843.8728029992,
"stddev": 766932.8494434259,
"p50": 78658,
"p75": 1614077,
"p95": 1614077,
"p98": 1614077,
"p99": 1614077,
"p999": 1614077
}
}
Learn more about using Helidon and MicroProfile metrics in the Metrics Guide.
Health Check
Helidon provides built-in support for health check endpoints. Obtain the built-in health check using the following URL:
Health check:
curl -s -X GET http://localhost:8080/health
{
"outcome": "UP",
"status": "UP",
"checks": [
{
"name": "deadlock",
"state": "UP",
"status": "UP"
},
{
"name": "diskSpace",
"state": "UP",
"status": "UP",
"data": {
"free": "381.23 GB",
"freeBytes": 409340088320,
"percentFree": "43.39%",
"total": "878.70 GB",
"totalBytes": 943491723264
}
},
{
"name": "heapMemory",
"state": "UP",
"status": "UP",
"data": {
"free": "324.90 MB",
"freeBytes": 340682920,
"max": "3.46 GB",
"maxBytes": 3715629056,
"percentFree": "97.65%",
"total": "408.00 MB",
"totalBytes": 427819008
}
}
]
}
Endpoints for readiness and liveness checks are also provided by default. Obtain the default results using these URLs, which return the same result as the previous example.:
Default readiness and liveness endpoints:
# readiness
curl -i -X GET http://localhost:8080/health/ready
# liveness
curl -i -X GET http://localhost:8080/health/live
Helidon allows the addition of custom health checks to applications. Create a
new class GreetHealthcheck.java with the following content:
Rebuild the application, make sure that the mp.conf has the greeting set to
something other than "Hello" and then run the application and check the
health:
Custom health check reporting unhealthy state:
curl -i -X GET http://localhost:8080/health/live
Now update the greeting to "Hello" using the following request, and then check
health again:
Update the greeting and check health again:
curl -i -X PUT -H "Content-Type: application/json" -d '{"greeting": "Hello"}' http://localhost:8080/greet/greeting
curl -i -X GET http://localhost:8080/health/live
Learn more about health checks in the Health Check Guide.
Build a Docker Image
To run the application in Docker (or Kubernetes), a Dockerfile is needed to
build a Docker image. To build the Docker image, you need to have Docker
installed and running on your system.
Add a new Dockerfile in the project root directory with the following content:
To create the Docker image, use the following command:
Docker build:
docker build -t helidon-mp-tutorial .
Make sure the application is shutdown if it was still running locally so that port 8080 will not be in use, then start the application in Docker using the following command:
Run Docker Image:
docker run --rm -p 8080:8080 helidon-mp-tutorial:latest
Try the application as before.
Try the application:
curl http://localhost:8080/greet/bob
{"message":"Howdee bob!"}
curl http://localhost:8080/health/ready
{"outcome":"UP","status":"UP","checks":[]}
Deploy the application to Kubernetes
If you don’t have access to a Kubernetes cluster, create or obtain access to one. Then deploy the example:
Verify connectivity to cluster:
kubectl cluster-info
kubectl get nodes
To deploy the application to Kubernetes, a Kubernetes YAML file that defines the deployment and associated resources is needed. In this case all that is required is the deployment and a service.
Create a file called app.yaml in the project’s root directory with the
following content:
This Kubernetes YAML file can be used to deploy the application to Kubernetes:
Deploy the application to Kubernetes:
kubectl create -f app.yaml
kubectl get pods # Wait for quickstart pod to be RUNNING
image entry in the example above to
include the Docker registry name. If the registry is private a Docker registry
secret will also be required.The step above created a service that is exposed using any available node port. Kubernetes allocates a free port. Lookup the service to find the port.
Lookup the service:
kubectl get service helidon-mp-tutorial
Note the PORTs. The application can be exercised as before but use the second port number (the NodePort) instead of 8080. For example:
Access the application:
curl -X GET http://localhost:31431/greet
If desired, the Kubernetes YAML file can also be used to remove the application from Kubernetes as follows:
Remove the application from Kubernetes:
kubectl delete -f app.yaml
Summary
This tutorial demonstrated how to build a new Helidon MP application, how to use Helidon and MicroProfile configuration, logging, metrics, and health checks. It also demonstrated how to package the application in a Docker image and run it in Kubernetes.
There were several links to more detailed information included in the tutorial. These links are repeated below and can be explored to learn more details about Helidon application development.