Create a Java REST API with Helidon
In this tutorial, I’ll show you how to create a secure REST API and native image with Helidon. You’ll see how to run a secure, OAuth 2.0-protected, Java REST API that allows JWT authentication. Then, I’ll compare its performance with Micronaut, Quarkus, and Spring Boot.
This tutorial is also available as a screencast.
Prerequisites:
-
SDKMAN (for Java 17 with GraalVM)
-
HTTPie (a better version of cURL)
-
An Okta Developer Account (or the Okta CLI)
The brackets at the end of some steps indicate the IntelliJ Live Templates I used in the video. You can find the template definitions at mraible/idea-live-templates. |
Install a JDK with GraalVM
Use SDKMAN to install Java 17 with GraalVM
sdk install java 22.1.0.r17-grl
Generate an OAuth 2.0 access token
-
Install the Okta CLI and run
okta register
to sign up for a new account. If you already have an account, runokta login
. -
Run
okta apps create spa
. Setoidcdebugger
as an app name and press Enter. -
Use
https://oidcdebugger.com/debug
for the Redirect URI and set the Logout Redirect URI tohttps://oidcdebugger.com
. -
Navigate to the OpenID Connect Debugger website.
-
Fill in your client ID
-
Use
https://{yourOktaDomain}/oauth2/default/v1/authorize
for the Authorize URI -
Select code for the response type and Use PKCE
-
Click Send Request to continue
-
-
Set the access token as a
TOKEN
environment variable in a terminal window.TOKEN=eyJraWQiOiJYa2pXdjMzTDRBYU1ZSzNGM...
Build a Java REST API with Helidon
-
Create a Helidon app with OAuth 2.0 support:
mvn -U archetype:generate -DinteractiveMode=false \ -DarchetypeGroupId=io.helidon.archetypes \ -DarchetypeArtifactId=helidon-quickstart-mp \ -DarchetypeVersion=2.5.0 \ -DgroupId=com.okta.rest \ -DartifactId=helidon \ -Dpackage=com.okta.rest
You can also install Helidon’s CLI and run helidon init
. -
Add MicroProfile JWT support in
pom.xml
:<dependency> <groupId>io.helidon.microprofile.jwt</groupId> <artifactId>helidon-microprofile-jwt-auth</artifactId> </dependency>
-
Add a
HelloResource
class that returns the user’s information: [h-hello
]package com.okta.rest.controller; import io.helidon.security.Principal; import io.helidon.security.SecurityContext; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import java.util.Optional; import static javax.ws.rs.core.MediaType.TEXT_PLAIN; @Path("/hello") public class HelloResource { @GET @Produces(TEXT_PLAIN) public String hello(@Context SecurityContext context) { Optional<Principal> userPrincipal = context.userPrincipal(); return "Hello, " + userPrincipal.get().getName() + "!"; } }
-
Add a
HelloApplication
class insrc/main/java/com/okta/rest
to register your resource and configure JWT authentication: [h-app
]package com.okta.rest; import com.okta.rest.controller.HelloResource; import org.eclipse.microprofile.auth.LoginConfig; import javax.enterprise.context.ApplicationScoped; import javax.ws.rs.core.Application; import java.util.Set; @LoginConfig(authMethod = "MP-JWT") @ApplicationScoped public class HelloApplication extends Application { @Override public Set<Class<?>> getClasses() { return Set.of(HelloResource.class); } }
-
Add your Okta endpoints to
src/main/resources/META-INF/microprofile-config.properties
.mp.jwt.verify.publickey.location=https://{yourOktaDomain}/oauth2/default/v1/keys mp.jwt.verify.issuer=https://{yourOktaDomain}/oauth2/default
Run and test your Helidon REST API with HTTPie
-
Start your app from your IDE or using a terminal:
mvn package && java -jar ./target/helidon.jar
-
Test your API with an access token.
http :8080/hello Authorization:"Bearer $TOKEN"
Build a native Helidon app with GraalVM
-
Compile your Helidon app into a native executable using the
native-image
profile:mvn package -Pnative-image
-
Start your Helidon app:
./target/helidon
-
Test your API with an access token.
http :8080/hello Authorization:"Bearer $TOKEN"
Startup time comparison
I compared startup times between frameworks by running each image three times before recording the numbers. Then, I ran each app five more times and averaged the results. I gathered these numbers on a 2019 MacBook Pro with an SSD, 2.4 GHz 8-Core Intel Core i9 processor, and 64 GB of RAM.
Versions used: Quarkus 2.9.0, Micronaut 3.4.3, Helidon 2.5.0, and Spring Boot 2.6.7 with Spring Native 0.11.5.
Memory usage comparison
I tested the memory usage (in megabytes) of each app using the command below. I ran it right after I started the app, after a single authenticated request, and after five authenticated requests.
ps -o pid,rss,command | grep --color <executable> | awk '{$2=int($2/1024)"M";}{ print;}'
The chart below shows the memory usage after five requests.
Comparing Native Java REST API Frameworks Live Stream
I missed Devoxx France this year, but I’m still doing my presentation! I’ll be live-streaming Comparing Native Java REST API Frameworks on June 7, 2022 at 6:00 MDT (14:00 CEST). Join me or watch the recorded version below!
Secure Native Java with Helidon FTW!
⚡️ Create a secure REST API with Helidon: okta start helidon
🚀 Find this example’s code on GitHub: @oktadev/native-java-examples/helidon
👀 Related blog post: Build REST APIs and Native Java Apps with Helidon
Okta Developer Blog Comment Policy
We welcome relevant and respectful comments. Off-topic comments may be removed.