Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Comparing Native Java REST API Frameworks - Atlanta JUG 2024

Comparing Native Java REST API Frameworks - Atlanta JUG 2024

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

January 16, 2024
Tweet

More Decks by Matt Raible

Other Decks in Programming

Transcript

  1. Matt Raible | @mraible January 16, 2024 Native Java REST

    API Comparison Micronaut, Quarkus, Spring Boot, and Helidon Photo by Christopher Alvarenga https://unsplash.com/photos/concrete-buildings-during-golden-hour-K5iyVtWYXqo
  2. @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 auth0.com/blog @mraible
  3. @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
  4. @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
  5. @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
  6. @mraible Get Started with Java 21 Better yet, use SDKMAN!

    curl -s https://get.sdkman.io | bash sdk install java 21-open
  7. 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() + "!"; } }
  8. @mraible Get Started with Quarkus sdk install quarkus quarkus create

    app com.okta.rest:quarkus \ --extension="smallrye-jwt,resteasy-reactive" --gradle
  9. 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() + "!"; } }
  10. Test Quarkus with HTTPie https://httpie.org gradle --console=plain quarkusDev http :8080/hello

    TOKEN=eyJraWQiOiJxOE1QMjFNNHZCVmxOSkxGbFFWNlN... http :8080/hello Authorization:"Bearer $TOKEN"
  11. @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 \ bootVersion==3.2.0 \ baseDir==spring-boot | tar -xzvf -
  12. @mraible Use the Spring Boot CLI sdk install springboot spring

    init -d=web,oauth2-resource-server,native \ --group-id=com.okta.rest -b=3.2.0 \ --package-name=com.okta.rest spring-boot
  13. 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() + "!"; } }
  14. Test Spring Boot with HTTPie https://httpie.org gradle bootRun http :8080/hello

    TOKEN=eyJraWQiOiJxOE1QMjFNNHZCVmxOSkxGbFFWNlN... http :8080/hello Authorization:"Bearer $TOKEN"
  15. @mraible Get Started with Helidon mvn -U archetype:generate -DinteractiveMode=false \

    -DarchetypeGroupId=io.helidon.archetypes \ -DarchetypeArtifactId=helidon-quickstart-mp \ -DarchetypeVersion=4.0.2 \ -DgroupId=com.okta.rest \ -DartifactId=helidon \ -Dpackage=com.okta.rest
  16. Use the Helidon CLI sdk install helidon helidon init --flavor

    MP \ --groupid com.okta.rest \ --artifactid helidon \ --package com.okta.rest --batch
  17. 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() + "!"; } }
  18. 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); } }
  19. 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"
  20. @mraible Startup Performance Milliseconds 0 500 1000 1500 2000 Micronaut

    Quarkus Spring Boot Helidon 1,097 953 418 389 789 728 1,346 369 Dev Startup (gradle or mvn) Packaged Startup (java -jar)
  21. @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/v4/mp/graphql
  22. @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
  23. @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-oidc-auth0-tutorial Spring Boot https://docs.spring.io/spring-security/reference/servlet/oauth2/login Helidon https://helidon.io/docs/v4/mp/security/providers#OIDC-Provider
  24. @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"]
  25. @mraible Build with Docker Build your image docker build -t

    <tag-name> . Run your image docker run -it -p 8080:8080 <tag-name>
  26. @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
  27. @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"
  28. @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
  29. @mraible Build with Docker Helidon generates three Docker-related files Dockerfile

    Dockerfile.jlink Dockerfile.native Helidon + Jib mvn compile jib:dockerBuild
  30. @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
  31. @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
  32. @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.28' }
  33. @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
  34. @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
  35. @mraible Native Startup Performance (M1; time from console) Milliseconds 0

    12 24 36 48 60 January 9, 2024 35.8 42.6 43.2 21.8 15.6 16.2 Micronaut 4.2.3 Micronaut (optimized) Quarkus 3.6.4 Spring Boot 3.2.0 Helidon 4.0.2 Helidon (optimized)
  36. @mraible Native Startup Performance (M1; scripted) Milliseconds 0 25 50

    75 100 January 9, 2024 53.8 66.6 71.4 48.2 51.2 49.2 Micronaut 4.2.3 Micronaut (optimized) Quarkus 3.6.4 Spring Boot 3.2.0 Helidon 4.0.2 Helidon (optimized)
  37. @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
  38. Build Docker Images with GitHub Actions https://github.com/oktadev/auth0-java-rest-api-examples/blob/main/.github/workflows/docker.yml steps: - name:

    Checkout code uses: actions/checkout@v4 - name: Setup GraalVM uses: graalvm/setup-graalvm@v1 with: java-version: '21' distribution: 'graalvm' github-token: $ {{ secrets.GITHUB_TOKEN }} - run: | echo "GRAALVM_HOME: $GRAALVM_HOME" echo "JAVA_HOME: $JAVA_HOME" java -- version - name: Build Micronaut project run: | cd micronaut ./gradlew dockerBuildNative docker tag app:latest mraible/micronaut:latest shell: bash
  39. @mraible Docker Startup Performance (AWS EC2 t2.micro) Milliseconds 0 40

    80 120 160 200 January 10, 2024 131.2 137.8 38.4 53.8 Micronaut 4.2.3 Quarkus 3.6.4 Spring Boot 3.2.0 Helidon 4.0.2
  40. @mraible Native Memory Used after 10 requests (M1) Megabytes 0

    30 60 90 120 150 January 9, 2024 73 93 87 52 67 66 Micronaut Micronaut (optimized) Quarkus Spring Boot Helidon Helidon (optimized)
  41. @mraible Docker Memory Used after 10 requests (EC2 t2.micro) Megabytes

    0 20 40 60 80 100 January 10, 2024 51 47 14 19 Micronaut Quarkus Spring Boot Helidon
  42. @mraible Stack Overflow Tags 0 45,000 90,000 135,000 180,000 January

    10, 2024 150 146,344 4,272 1,743 Micronaut Quarkus Spring Boot Helidon
  43. @mraible GitHub Stars 0 20,000 40,000 60,000 80,000 January 10,

    2024 3,300 71,200 12,700 5,900 Micronaut Quarkus Spring Boot Helidon
  44. @mraible Jobs on Indeed (US) 0 2,500 5,000 January 10,

    2024 28 3,477 48 52 Micronaut Quarkus Spring Boot Helidon
  45. @mraible Twitter Followers 0 30,000 60,000 90,000 120,000 January 10,

    2024 4,746 104,700 18,700 13,300 Micronaut Quarkus Spring Boot Helidon
  46. @mraible JHipster Support 🤓 Spring Boot 3 - JHipster 8

    is now available! 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!
  47. @mraible What I found this time 🐳 Had to forcibly

    remove Docker containers on EC2 to get the latest 🚀 The optimized Micronaut app starts slower than the non-optimized app 🌱 Spring Boot 3.2.1 doesn't work with GraalVM when using web + security 🔮 Helidon needs -H:+AddAllCharsets added to properties 🤥 The frameworks are filthy liars when it comes to printed startup times
  48. @mraible 🏆 Quarkus provides the best developer joy and memory

    usage 🚀 Micronaut is consistently competitive with Quarkus 🌱 Spring Boot has the strongest community, ecosystem, and growth 🔮 Helidon is competitive with Spring Boot but not very popular My Thoughts
  49. @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
  50. Make login our problem. Not yours. How we can help:

    Authorization Authentication Security Try Auth0 for free! Up to 7,500 monthly active users. Unlimited user logins. Includes passkeys support. No credit card required. Special Plans for Startups & Nonprofits