Quarkus REST with Apache Camel and Keycloak
In this article, you’ll learn how to build a REST API using Apache Camel on top of Quarkus. We’ll cover the Camel REST DSL with the platform-http component, data persistence with Hibernate Panache, authentication with Quarkus OIDC and Keycloak Dev Services, and a few non-obvious tricks needed to make Swagger UI work correctly with Camel routes. Above all, I’d like to show you how easy it is to build and test a Camel and OIDC-based application using Quarkus.
Are you interested in other articles about Quarkus? In this blog post, you’ll find an introduction to Quarkus and Keycloak. Follow this link to read my latest article on Quarkus, which explains how to use MCP with the LangChain4j framework.
Do you want to deploy your Quarkus application on Kubernetes following best practices? Read my latest book, Hands-On Java with Kubernetes.
Source Code
Feel free to use my source code if you’d like to try it out yourself. To do that, you must clone my sample GitHub repository. The application source resides in the person-rest-api directory. Once you clone it, follow my instructions.
Maven Dependencies
The project uses Quarkus 3.36 and Java 25. Because Camel has its own BOM separate from Quarkus, you need to import both into dependencyManagement.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId>
<version>3.36.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-camel-bom</artifactId>
<version>3.36.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>XMLWe can split runtime dependencies into three groups. The Camel group covers the REST DSL and the HTTP transport, backed by Quarkus’s own Vert.x server, Jackson for JSON binding, the direct component for in-process routing, and the bean component to delegate to CDI beans.
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-platform-http</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-direct</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-bean</artifactId>
</dependency>XMLThe persistence group uses Hibernate ORM with Panache and an H2 in-memory database. Security uses quarkus-oidc, which automatically provisions a Keycloak container in dev mode. Finally, OpenAPI documentation requires both quarkus-smallrye-openapi and camel-quarkus-openapi-java. The reason for needing both is explained in the Swagger section below.
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-h2</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-openapi-java</artifactId>
</dependency>XMLData ORM Model with Quarkus Panache
The Person entity uses Quarkus Panache’s active record pattern. Because the PanacheEntity class already provides the id field and all CRUD methods as static calls on the entity class itself, the model is just field declarations.
@Entity
public class Person extends PanacheEntity {
public String firstName;
public String lastName;
public String email;
public int age;
public String gender;
}JavaPersonService is a standard CDI bean. Because Camel invokes its methods via the bean component, you can use the @Header annotation directly on method parameters to pull path variables out of the Camel exchange without writing any routing logic.
@ApplicationScoped
public class PersonService {
public List<Person> findAll() {
return Person.listAll();
}
public Person findById(@Header("id") Long id) {
return Person.findById(id);
}
@Transactional
public Person create(Person person) {
person.persist();
return person;
}
@Transactional
public Person update(@Header("id") Long id, Person person) {
Person existing = Person.findById(id);
if (existing == null) return null;
existing.firstName = person.firstName;
existing.lastName = person.lastName;
existing.email = person.email;
existing.age = person.age;
existing.gender = person.gender;
return existing;
}
@Transactional
public void delete(@Header("id") Long id) {
Person.deleteById(id);
}
}JavaCamel Route with REST DSL
The ApiRoute class is the core of the application. It wires together HTTP endpoints, request/response logging, and the service bean calls.
@ApplicationScoped
public class ApiRoute extends RouteBuilder {
@Inject
PersonService personService;
@Override
public void configure() {
interceptFrom()
.log(LoggingLevel.INFO, "pl.piomin.services.ApiRoute",
">>> [${header.CamelHttpMethod}] ${header.CamelHttpUri} body=${body}");
onCompletion()
.log(LoggingLevel.INFO, "pl.piomin.services.ApiRoute",
"<<< response body=${body}");
restConfiguration()
.component("platform-http")
.bindingMode(RestBindingMode.json);
rest("/persons")
.security("SecurityScheme")
.get().description("Get all persons").to("direct:getPersons")
.get("/{id}").description("Get person by id").to("direct:getPersonById")
.post().description("Create person").type(Person.class).to("direct:createPerson")
.put("/{id}").description("Update person").type(Person.class).to("direct:updatePerson")
.delete("/{id}").description("Delete person").to("direct:deletePerson");
from("direct:getPersons").bean(personService, "findAll");
from("direct:getPersonById").bean(personService, "findById");
from("direct:createPerson").bean(personService, "create");
from("direct:updatePerson").bean(personService, "update");
from("direct:deletePerson").bean(personService, "delete");
}
}JavaThere are a few things worth pointing out here.
- The
interceptFrom()method intercepts every incoming exchange before it reaches any route, so a single log statement covers all five endpoints without repeating it in each from()block. - The
restConfiguration().component("platform-http")line is critical for running in Quarkus. Because Quarkus already manages a Vert.x HTTP server, using theplatform-http. - Each REST operation uses the direct: component to fan out to a named in-process route. This indirection is intentional — it keeps the REST DSL declaration clean and makes each
The application protects all /persons* paths with an authenticated policy. To achieve this, we must add the following two properties to the application.properties file.
quarkus.http.auth.permission.api.paths=/persons*
quarkus.http.auth.permission.api.policy=authenticatedPlaintextIn dev mode, you do not need to install or configure Keycloak manually. Because quarkus-oidc is on the classpath, Quarkus Dev Services automatically starts a Keycloak container with a pre-configured realm and a client named quarkus-app. You only need to pin the port so the Swagger UI OAuth redirect URL stays predictable:
quarkus.keycloak.devservices.port=8180PlaintextWhen you start the application with mvn quarkus:dev Quarkus Dev UI is available at http://localhost:8080/q/dev-ui. It shows all active extensions, their configurations, and, in this application, the Camel route graph and the Keycloak realm details provisioned by Dev Services.

Go to the Keycloak provider in the OpenID Connect tile. Then, log in to the Keycloak instance running as a container on your machine. Use alice / alice credentials.

Then, you can test all your REST endpoints with an access token generated by Keycloak for a given user.

Integrate Quarkus Camel with Swagger OpenAPI
Getting Swagger UI to work correctly with Camel routes requires a specific configuration that is easy to get wrong. There are two separate OpenAPI integrations in this project, and each serves a different role. The camel-quarkus-openapi-java extension generates the OpenAPI spec from the Camel REST DSL. The quarkus-smallrye-openapi extension generates an OpenAPI spec from Quarkus REST endpoints. By default, Quarkus SmallRye would not include any of the Camel-defined routes — it only sees JAX-RS resources. However, this method of generating Swagger has one key advantage over the Camel-based model. It recognizes Quarkus-specific dependencies, such as Quarkus OIDC, and accounts for them when generating the OpenAPI spec. So, you should explicitly enable Camel’s OpenAPI spec exposure to Quarkus SmallRye with the following property:
quarkus.camel.openapi.expose.enabled=truePlaintextThat’s not all. After setting the property above, Quarkus merges the OpenAPI spec generated for Quarkus REST endpoints and the Camel REST DSL. So in this case, we must also include the quarkus-rest-jackson extension to the Maven dependencies to make it work. The .security("SecurityScheme") call in the route builder is the second non-obvious piece. This adds a security requirement to every operation in the generated spec. The name SecurityScheme is the default name generated by Quarkus SmallRye when detecting the OIDC module.
rest("/persons")
.security("SecurityScheme")
.get()
.description("Get all persons")
.to("direct:getPersons")JavaNow, you can go to http://localhost:8080/q/swagger-ui to see the OpenAPI spec for all your Camel REST endpoints. Then you can click the Authorize button to authenticate with Keycloak OIDC.

You can choose from several different authorization methods. In this case, use the alice user and the quarkus-app client.

Finally, you can call any of your endpoints using an automatically generated access token thanks to the integration between Quarkus SmallRye, Keycloak, and Apache Camel.

Conclusion
In this article, you saw how to use the Camel REST DSL with the platform-http component to register routes on the Quarkus server and integrate your app with Keycloak and Swagger. You learned how to build and test an app with Quarkus in developer mode and how to generate a complete OpenAPI spec that automatically integrates with OIDC.



Related Posts