Lab 1 – Hello Flow & Dev UI

In this lab you:

  • Create (or reuse) a Quarkus app.

  • Add the Quarkus Flow extension.

  • Write a minimal workflow using the Java DSL.

  • Invoke it via REST and inspect it in Quarkus Dev UI.

1. Create the Quarkus project

If you don’t have a project yet, use the Quarkus CLI:

quarkus create app org.acme:hello-flow \
  --extension=resteasy-reactive-jackson,io.quarkiverse.flow:quarkus-flow
cd hello-flow

Or add RESTEasy Reactive with JSON to an existing project.

2. Create a minimal workflow

Create a Flow subclass that returns a simple greeting. For example:

package org.acme;

import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.set;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkiverse.flow.Flow;
import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder;

@ApplicationScoped
public class HelloWorkflow extends Flow {
    @Override
    public Workflow descriptor() {
        return FuncWorkflowBuilder.workflow("hello")
                // jq expression to set our context to the JSON object `message`
                .tasks(set("{ message: \"hello world!\" }"))
                .build();
    }
}

This workflow builds a simple do sequence with one task that sets message = "hello world!" and returns it as the workflow output.

3. Expose it through REST

Create a REST resource that injects the workflow and starts an instance:

package org.acme;

import java.util.Map;
import java.util.concurrent.CompletionStage;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.jboss.resteasy.reactive.ResponseStatus;

@Path("/hello")
@ApplicationScoped
public class HelloResource {

    @Inject
    HelloWorkflow hello; // inject the Flow subclass

    @GET
    @ResponseStatus(200)
    public CompletionStage<Message> hello() {
        return hello
                .startInstance(Map.of()) // convenience on Flow
                .thenApply(w -> w.as(Message.class).orElseThrow());
    }
}

Key points:

  • The resource injects the HelloWorkflow class directly.

  • startInstance() starts the workflow and returns a CompletionStage.

  • The method returns CompletionStage<String> so the endpoint stays non-blocking.

4. Run in dev mode

Start Quarkus in dev mode:

./mvnw quarkus:dev

Test the endpoint:

curl http://localhost:8080/hello

You should see a JSON output similar to:

{"message":"hello world!"}

5. Explore Quarkus Dev UI

With dev mode still running, open the Dev UI in your browser:

Look for the Flow card (if available in your version). From there you can:

  • Inspect available workflows.

  • Trigger them with custom input data.

Even without a dedicated card, you can:

  • Hit the REST endpoint from the Dev UI REST Client panel (if you expose an OpenAPI description).

  • Watch logs and tracing output as the workflow runs.

6. What you learned

  • Quarkus Flow discovers Flow subclasses at build time and makes them injectable.

  • You can expose workflows through normal Quarkus REST endpoints using CompletionStage.

  • Dev UI gives you a convenient front-end for iterating on workflows while in dev mode.