Share
Embed
Comparing Native Java REST API Frameworks - Philadelphia JUG 2023
Use Spring Boot! No, use Micronaut!! Nooooo, Quarkus is the best!!! What about Helidon?
Many developers praise the hottest and fastest Java REST frameworks: Micronaut, Quarkus, Spring Boot, and Helidon. In this session, you'll learn how to do the following with each framework:
✅ Build a REST API
✅ Secure your API with OAuth 2.0
✅ Optimize for production with Docker and GraalVM
I'll also share some performance numbers and pretty graphs to compare community metrics.
GitHub repo: https://github.com/oktadev/auth0-java-rest-api-examples
Demo script: @oktadev/auth0-java-rest-api-examples/blob/main/demo.adoc
Matt Raible
October 17, 2023
Transcript
89 slides
-
Matt Raible | @mraible October 17, 2023 Native Java REST
API Comparison Micronaut, Quarkus, Spring Boot, and Helidon Photo by Dan Mall https://unsplash.com/photos/JsquWCJ4h9Y -
@mraible Who is Matt Raible? Father, Husband, Skier, Mountain Biker,
Whitewater Rafter Bus Lover Web Developer and Java Champion Developer Advocate Architect Blogger on raibledesigns.com and developer.okta.com/blog @mraible -
@mraible Today’s Agenda Why Java? Build { REST, GraphQL }
APIs with Java Secure your APIs with OAuth 2.1 Build with Docker Go Native with GraalVM https://unsplash.com/photos/JsTmUnHdVYQ -
@mraible Why Java? 25+ Years of use, abuse, and improvements
Open Source code is available; many popular open source frameworks and tools Hugely Popular and widely used by many enterprises and web-scale companies -
@mraible Download the Oracle builds of OpenJDK https://jdk.java.net/21 Or Eclipse
builds from Adoptium https://adoptium.net Get Started with Java 21 -
@mraible Get Started with Java 21 Better yet, use SDKMAN!
curl -s https://get.sdkman.io | bash sdk install java 21-open -
@mraible sdk install micronaut mn create-app com.okta.rest.app \ -f security-jwt
-f micronaut-aot Get Started with Micronaut -
package com.okta.rest.controller; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.Produces;
import io.micronaut.security.annotation.Secured; import io.micronaut.security.rules.SecurityRule; import java.security.Principal; @Controller("/hello") public class HelloController { @Get @Secured(SecurityRule.IS_AUTHENTICATED) @Produces(MediaType.TEXT_PLAIN) public String hello(Principal principal) { return "Hello, " + principal.getName() + "!"; } } -
Test Micronaut with HTTPie https://httpie.org gradle run http :8080/hello TOKEN=eyJraWQiOiJxOE1QMjFNNHZCVmxOSkxGbFFWNlN...
http :8080/hello Authorization:"Bearer $TOKEN" -
@mraible Get Started with Quarkus sdk install quarkus quarkus create
app com.okta.rest:quarkus \ --extension="smallrye-jwt,resteasy-reactive" --gradle -
@mraible mvn io.quarkus:quarkus-maven-plugin:3.4.3:create \ -DprojectGroupId=com.okta.rest \ -DprojectArtifactId=quarkus \ -DclassName="com.okta.rest.HelloResource" \
-Dpath="/hello" \ -Dextensions="smallrye-jwt,resteasy-reactive" Get Started with Quarkus -
package com.okta.rest; import io.quarkus.security.Authenticated; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.SecurityContext; import java.security.Principal; @Path("/hello") public class HelloResource { @GET @Authenticated @Produces(MediaType.TEXT_PLAIN) public String hello(@Context SecurityContext context) { Principal userPrincipal = context.getUserPrincipal(); return "Hello, " + userPrincipal.getName() + "!"; } } -
Test Quarkus with HTTPie https://httpie.org gradle --console=plain quarkusDev http :8080/hello
TOKEN=eyJraWQiOiJxOE1QMjFNNHZCVmxOSkxGbFFWNlN... http :8080/hello Authorization:"Bearer $TOKEN" -
@mraible Get Started with Spring Boot https start.spring.io/starter.tgz \ dependencies==web,oauth2-resource-server,native
\ packageName==com.okta.rest \ name==spring-boot \ baseDir==spring-boot | tar -xzvf - -
@mraible Use the Spring Boot CLI sdk install springboot spring
init -d=web,oauth2-resource-server,native \ --group-id=com.okta.rest \ --package-name=com.okta.rest spring-boot -
package com.okta.rest.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.security.Principal; @RestController public
class HelloController { @GetMapping("/hello") public String hello(Principal principal) { return "Hello, " + principal.getName() + "!"; } } -
Test Spring Boot with HTTPie https://httpie.org gradle bootRun http :8080/hello
TOKEN=eyJraWQiOiJxOE1QMjFNNHZCVmxOSkxGbFFWNlN... http :8080/hello Authorization:"Bearer $TOKEN" -
@mraible Get Started with Helidon mvn -U archetype:generate -DinteractiveMode=false \
-DarchetypeGroupId=io.helidon.archetypes \ -DarchetypeArtifactId=helidon-quickstart-mp \ -DarchetypeVersion=3.2.2 \ -DgroupId=com.okta.rest \ -DartifactId=helidon \ -Dpackage=com.okta.rest -
Use the Helidon CLI sdk install helidon helidon init --flavor
MP \ --groupid com.okta.rest \ --artifactid helidon \ --package com.okta.rest --batch -
package com.okta.rest.controller; import io.helidon.security.Principal; import io.helidon.security.annotations.Authenticated; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context; @Path("/hello") public class HelloResource { @Authenticated @GET public String hello(@Context SecurityContext context) { return "Hello, " + context.userName() + "!"; } } -
package com.okta.rest; import com.okta.rest.controller.HelloResource; import org.eclipse.microprofile.auth.LoginConfig; import jakarta.enterprise.context.ApplicationScoped; import jakarta.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); } } -
Test Helidon with HTTPie https://httpie.org mvn package && java -jar
target/helidon.jar http :8080/hello TOKEN=eyJraWQiOiJxOE1QMjFNNHZCVmxOSkxGbFFWNlN... http :8080/hello Authorization:"Bearer $TOKEN" -
@mraible Startup Performance Milliseconds 0 500 1000 1500 2000 Micronaut
Quarkus Spring Boot Helidon 1,053 952 430 433 896 743 1,402 399 Dev Startup (gradle or mvn) Packaged Startup (java -jar) -
@mraible What about GraphQL APIs? Why GraphQL? Does your favorite
framework support GraphQL? Micronaut https://micronaut-projects.github.io/micronaut-graphql/latest/guide Quarkus https://quarkus.io/guides/smallrye-graphql Spring Boot https://spring.io/projects/spring-graphql Helidon https://helidon.io/docs/v3/#/mp/graphql -
@mraible Secure your API with OAuth 2.1 https://oauth.net/2.1 PKCE is
required for all clients using the authorization code flow Redirect URIs must be compared using exact string matching The Implicit grant is omitted from this specification The Resource Owner Password Credentials grant is omitted from this specification Bearer token usage omits the use of bearer tokens in the query string of URIs Refresh tokens for public clients must either be sender-constrained or one-time use -
@mraible Authenticate with OpenID Connect (OIDC) What is OpenID Connect?
Does your favorite framework support OIDC authentication? Micronaut https://guides.micronaut.io/latest/micronaut-oauth2-auth0.html Quarkus https://quarkus.io/guides/security-openid-connect-web-authentication Spring Boot https://docs.spring.io/spring-security/reference/servlet/oauth2/login Helidon https://helidon.io/docs/v3/#/mp/security/providers#OIDC-Provider -
@mraible Build with Docker Create a Dockerfile FROM openjdk:21-alpine
ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} app.jar EXPOSE 8080 ENTRYPOINT ["java","-jar","/app.jar"] -
@mraible Build with Docker Build your image docker build -t
<tag-name> . Run your image docker run -it -p 8080:8080 <tag-name> -
@mraible Build with Docker: Jib Get Jibby with it! mvn
verify jib:build gradle jib Or build directly to your Docker daemon mvn verify jib:dockerBuild gradle jibDockerbuild https://github.com/GoogleContainerTools/jib -
@mraible Build with Docker Micronaut uses Jib, but you must
configure plugins Quarkus generates four Docker-related files Dockerfile.jvm Dockerfile.legacy-jar Dockerfile.native Dockerfile.native-micro Quarkus + Jib mvn quarkus:add-extension -Dextensions="container-image-jib" gradle addExtension --extensions="container-image-jib" -
@mraible Build with Docker Spring Boot 2.3+ has built-in support
mvn -Pnative spring-boot:build-image gradle bootBuildImage Uses layered JARs for faster builds dependencies snapshot-dependencies resources application https://spring.io/blog/2020/01/27/creating-docker-images-with-spring-boot-2-3-0-m1 -
@mraible Build with Docker Helidon generates three Docker-related files Dockerfile
Dockerfile.jlink Dockerfile.native Helidon + Jib Not available -
@mraible Use Micronaut CLI mn create-app ... mvn package -Dpackaging=native-image
gradle nativeImage gradle dockerBuildNative Go Native with GraalVM and Micronaut https://docs.micronaut.io/latest/guide/#graal -
@mraible Go Native with GraalVM and Quarkus Create an executable
without GraalVM installed mvn package -Dnative -Dquarkus.native.container-build=true gradle build -Dquarkus.package.type=native \ -Dquarkus.native.container-build=true Then, build the image docker build -f src/main/docker/Dockerfile.native -t \ <tag-name> . And run it docker run -it -p 8080:8080 <tag-name> https://quarkus.io/guides/building-native-image -
@mraible Use start.spring.io to get plugins Go Native with GraalVM
and Spring Boot <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> plugins { ... id 'org.graalvm.buildtools.native' version '0.9.27' } -
@mraible Go Native with GraalVM and Spring Boot Build the
native application mvn native:compile -Pnative gradle nativeCompile Build an image and Docker container mvn spring-boot:build-image -Pnative gradle bootBuildImage -
@mraible Build the image docker build -f Dockerfile.native -t <tag-name>
. And run it docker run --rm -p 8080:8080 <tag-name> Go Native with GraalVM and Helidon -
@mraible Native Startup Performance (M1; time from console) Milliseconds 0
12 24 36 48 60 October 17, 2023 23.8 49.2 38.4 27.8 16 16.2 Micronaut 4.1.4 Micronaut (optimized) Quarkus 3.4.3 Spring Boot 3.1.4 Helidon 3.2.2* Helidon (optimized) -
@mraible Native Startup Performance (M1; scripted) Milliseconds 0 25 50
75 100 October 17, 2023 59.8 58.6 66 56.4 51.6 49.4 Micronaut 4.1.4 Micronaut (optimized) Quarkus 3.4.3 Spring Boot 3.1.4 Helidon 3.2.2* Helidon (optimized) -
@mraible t2.small: 1 vCPUs and 2 GiB RAM - Fails
to build any projects t2.medium: 2 vCPUs and 4 GiB RAM - Quarkus and Spring Boot fail to build; Helidon took too long t2.large: 2 vCPUs and 8 GiB RAM 🌟 Building GraalVM images on AWS -
@mraible Native Startup Performance (AWS EC2 t2.large) Milliseconds 0 20
40 60 80 100 October 17, 2023 94.6 41 42.4 41.2 Micronaut 4.1.4 Micronaut (optimized) Quarkus 3.4.3 Spring Boot 3.1.4 -
@mraible Native Memory Used after 5 requests (M1) Megabytes 0
30 60 90 120 150 October 17, 2023 123 117 84 53 64 64 Micronaut Micronaut (optimized) Quarkus Spring Boot Helidon Helidon (optimized) -
@mraible Native Memory Used after 5 requests (EC2 t2.large) Megabytes
0 30 60 90 120 150 October 17, 2023 91 57 70 71 Micronaut Micronaut (optimized) Quarkus Spring Boot -
@mraible Stack Overflow Tags 0 45,000 90,000 135,000 180,000 October
17, 2023 139 144,464 4,112 1,704 Micronaut Quarkus Spring Boot Helidon -
@mraible GitHub Stars 0 20,000 40,000 60,000 80,000 October 17,
2023 3,200 69,700 12,400 5,800 Micronaut Quarkus Spring Boot Helidon -
@mraible Jobs on Indeed (US) 0 2,500 5,000 October 17,
2023 15 3,985 65 48 Micronaut Quarkus Spring Boot Helidon -
@mraible Twitter Followers 0 30,000 60,000 90,000 120,000 October 17,
2023 4,531 103,300 18,400 13,300 Micronaut Quarkus Spring Boot Helidon -
@mraible JHipster Support 🤓 Spring Boot 3 - JHipster 8.0.0-rc1,
8.0.0 coming soon! Micronaut blueprint - github.com/jhipster/generator-jhipster-micronaut - v2.0.0 for Micronaut 3, 19 releases, 20 contributors, 495 commits - v3.0.0 with Micronaut 4 with JHipster 8 is next! Quarkus blueprint - github.com/jhipster/generator-jhipster-quarkus - v2.0.0 for Quarkus 2, 7 releases, 18 contributors, 653 commits - v3.0.0 with Quarkus 3 is on the horizon! -
@mraible 🏆 Quarkus provides the best developer joy and memory
usage 🚀 Micronaut is consistently competitive and 4.0 starts the fastest! 🌱 Spring Boot has the strongest community, ecosystem, and growth 🔮 Helidon has a lot of catching up to do ⚡ Spring Boot 3 not as fast as expected My Thoughts -
@mraible Action! New to Java? Try Spring Boot Know Spring?
Trial migration paths Testing is important, invest early and often Design your apps with security in mind Use OpenID Connect and OAuth 2.1 https://unsplash.com/photos/JsTmUnHdVYQ -
Thanks! Keep in Touch raibledesigns.com @mraible Presentations speakerdeck.com/mraible Code github.com/oktadev
developer.okta.com developer.auth0.com