Quarkus for Architects who Sometimes Write Code - Setup

Set Up Your Dev Environment

At a minimum, you are going to need the following:

  1. Git CLI: https://git-scm.com

  2. An IDE, I will be using Visual Studio Code: https://code.visualstudio.com

    Note: I’ve installed the following extensions for my Java development:

    • Extension Pack for Java
    • Lombok Annotations Support for VS Code
    • OpenShift Extension Pack
    • Quarkus Tools for Visual Studio Code
    • YAML
  3. Java - I’m using OpenJDK 17 https://adoptium.net

    Note: We’re going to be using the Java record type. So, you need at least Java 14. Java 17 is the current LTS release, so I am using that.

  4. Maven build tool: https://maven.apache.org

    Note: Make sure that Maven uses the correct Java version. Your $JAVA_HOME needs to resolve correctly.

  5. The Quarkus CLI: https://quarkus.io/guides/cli-tooling

  6. YQ for parsing and manipulating YAML. https://mikefarah.gitbook.io/yq/

  7. JQ for parsing and manipulating JSON.

  8. Curl for interacting with HTTP endpoints from the command line. (This is likely already part of your base OS)

MacBook Setup

If you are on a MacBook like I am, this will install the CLI tools and Java:

Note: If you already have one or more JDKs installed, the following might mess up your setup. These instructions are for a clean install.

  1. Install HomeBrew if you don’t have it already:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
  2. Install the tools:

    brew install jq yq maven openjdk@17 git quarkusio/tap/quarkus
    
  3. Fix Maven JDK version on Mac OS:

    HomeBrew installs the latest OpenJDK as a dependency for Maven. We don’t want Maven to use a different JDK.

    brew uninstall --ignore-dependencies openjdk
    

    In the next step we’ll set JAVA_HOME so that Maven uses the default JDK. In this case OpenJDK 17.

  4. Set your $PATH

    cat << EOF >> ~/.zshrc
    ### Brew Vars
    PATH="/usr/local/opt/openjdk@17/bin:\$PATH"
    export CPPFLAGS="-I/usr/local/opt/openjdk@17/include"
    export JAVA_HOME=$(/usr/libexec/java_home)
    ###
    EOF
    

Install my code prototyping helper script

In these Quarkus examples I will be using one of the utility scripts that I wrote for managing tasks in my own home lab. You don’t need to install the whole project right now, but you’ll need it later if you decide to set up your own OpenShift cluster and developer tooling.

The scripts and home lab configuration files are at: https://github.com/cgruver/kamarotos

The only script from that bundle that we need is: https://raw.githubusercontent.com/cgruver/kamarotos/main/bin/code

Do the following to install it:

  1. Create a working directory for these Quarkus examples:

    mkdir -p ${HOME}/okd-lab/bin
    mkdir ${HOME}/okd-lab/quarkus-projects
    

    Note: I’m being prescriptive here to keep things consistent with my other lab projects on this site.

  2. Grab the helper script:

    curl -o ${HOME}/okd-lab/bin/code -fsSL https://raw.githubusercontent.com/cgruver/kamarotos/main/bin/code
    chmod 700 ${HOME}/okd-lab/bin/code
    
  3. Now, edit your ~/.zshrc or ~/.bashrc file and add ${HOME}/okd-lab/bin to your $PATH

    For example:

    echo "PATH=$PATH:${HOME}/okd-lab/bin" >> ~/.zshrc
    

Description of my code project bootstrapping script

The script that you just grabbed is very opinionated toward the way I like to organize my code when I am prototyping. It also wraps the Quarkus CLI, and includes a couple of functions for adding properties and dependencies to a pom.xml. I really hate manually modifying the POM file… It’s just a quirk of mine… so I wrote a couple of functions to do the most common tasks.

As I mentioned, this script wraps the Quarkus CLI to bootstrap your project structure.

I am using quarkus it in an opinionated way:

quarkus create app --maven --java=${JAVA_VER} --no-wrapper --no-code --package-name=${GROUP_ID}.${APP_NAME} --extensions=${EXTENSIONS} ${QUARKUS_VERSION} ${GROUP_ID}:${APP_NAME}:0.1

To see the script in action, run:

code --create -b -a=apiclient -g=fun.is.quarkus -x=scheduler

This creates a basic REST service structure and includes the Quarkus Scheduler extension.

The base extensions that I include with the -b option are: resteasy-reactive-jackson, rest-client-reactive-jackson, smallrye-health, and config-yaml.

I use config-yaml mainly just to remind folks that you can use YAML, and JSON for that matter, for your application config files. While it creates a less compact file than the path.property=value that you are likely used to, it does lend itself to automation.

You’ll also notice that I’m using Maven, not Gradle. No particular reason, I just haven’t had a good reason to switch. I don’t have an opinion in the Gradle vs. Maven death match.

I’m also creating an opinionated directory structure:

apiserver
├── README.md
├── pom.xml
└── src
    ├── main
    │   ├── docker
    │   │   ├── Dockerfile.jvm
    │   │   ├── Dockerfile.legacy-jar
    │   │   ├── Dockerfile.native
    │   │   └── Dockerfile.native-micro
    │   ├── java
    │   │   └── fun
    │   │       └── is
    │   │           └── quarkus
    │   │               └── apiserver
    │   │                   ├── aop
    │   │                   ├── api
    │   │                   ├── collaborators
    │   │                   ├── dto
    │   │                   ├── event
    │   │                   ├── mapper
    │   │                   ├── model
    │   │                   └── service
    │   └── resources
    │       └── application.yml
    └── test
        └── java
            └── fun
                └── is
                    └── quarkus
                        └── apiserver

The subdirectories under src/main/java are intended to be used as follows:

Directory Description
aop AOP Interceptors
api Java Interfaces that define the API resources exposed by this application
collaborators Java Interfaces that define the API resources consumed by this application
dto Java Record Interfaces that define the JSON payloads produced or consumed by this application
event Messaging handlers, for example: Kafka or Event Bus
mapper Java Interfaces that define Mapstruct mappings from DTO to Entity
model The Entity objects that define the persistence model for this application
service The Objects that contain the business logic for this application

Love it or hate it… This is how I like to organize my code. So, there you have it. ;-)