Apache Camel: REST DSL

The Camel REST DSL lets you declare RESTful HTTP endpoints in a clean, readable style: directly inside your RouteBuilder. Camel translates these declarations into routes backed by any HTTP component (Netty, Undertow, Servlet, or camel-rest-starter). You get full EIP power inside each endpoint handler while keeping the API contract readable and separate.

Contents

Setup & Dependencies

Add camel-spring-boot-starter plus a REST transport. The camel-servlet-starter plugs into Spring Boot's embedded Tomcat with zero extra config.

XML
<!-- Core Camel Spring Boot -->
<dependency>
    <groupId>org.apache.camel.springboot</groupId>
    <artifactId>camel-spring-boot-starter</artifactId>
</dependency>

<!-- REST transport via Spring MVC / embedded Tomcat -->
<dependency>
    <groupId>org.apache.camel.springboot</groupId>
    <artifactId>camel-servlet-starter</artifactId>
</dependency>

<!-- JSON data-format for binding -->
<dependency>
    <groupId>org.apache.camel.springboot</groupId>
    <artifactId>camel-jackson-starter</artifactId>
</dependency>
Properties
# application.properties
camel.servlet.mapping.context-path=/api/*
camel.springboot.main-run-controller=true

Defining REST Endpoints

Use rest() inside a RouteBuilder to declare verbs and paths. The restConfiguration() call sets the component and base path once for all routes.

Java
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class OrderRestRoute extends RouteBuilder {

    @Override
    public void configure() {

        restConfiguration()
            .component("servlet")
            .bindingMode(RestBindingMode.json) // auto marshal/unmarshal JSON
            .dataFormatProperty("prettyPrint", "true")
            .port(8080)
            .contextPath("/api");

        rest("/orders")
            .description("Order service API")

            .get("/")
                .description("List all orders")
                .to("direct:getAllOrders")

            .get("/{id}")
                .description("Get order by ID")
                .to("direct:getOrder")

            .post("/")
                .description("Create a new order")
                .type(Order.class)
                .to("direct:createOrder")

            .delete("/{id}")
                .description("Delete an order")
                .to("direct:deleteOrder");
    }
}
The to("direct:...") calls keep REST declarations clean: actual processing logic lives in separate from("direct:...") routes.

Path & Query Parameters

Path parameters are automatically extracted from the URI and placed in message headers. Use header("id") inside the route to read them.

Java
from("direct:getOrder")
    .log("Looking up order: ${header.id}")
    .process(exchange -> {
        String id = exchange.getIn().getHeader("id", String.class);
        Order order = orderService.findById(id);
        exchange.getIn().setBody(order);
    });
Java
// Query parameters are also in headers
// GET /api/orders?status=PENDING
rest("/orders")
    .get("/search")
        .param().name("status").type(RestParamType.query).required(false).endParam()
        .to("direct:searchOrders");

from("direct:searchOrders")
    .process(exchange -> {
        String status = exchange.getIn().getHeader("status", String.class);
        exchange.getIn().setBody(orderService.findByStatus(status));
    });

JSON Binding with Jackson

With bindingMode(RestBindingMode.json) set, Camel automatically deserializes the request body into the declared type() class and serializes the response body back to JSON.

Java
public class Order {
    private String id;
    private String product;
    private int quantity;
    private String status;
    // getters and setters
}

// In RouteBuilder:
rest("/orders")
    .post("/")
        .type(Order.class)          // deserialize request JSON → Order
        .outType(Order.class)       // serialize response Order → JSON
        .to("direct:createOrder");

from("direct:createOrder")
    .process(exchange -> {
        Order order = exchange.getIn().getBody(Order.class);
        order.setId(UUID.randomUUID().toString());
        order.setStatus("CREATED");
        Order saved = orderService.save(order);
        exchange.getIn().setBody(saved);
    });
Setting both type() and outType() allows Camel to generate accurate OpenAPI schemas for the request and response bodies.

Connecting REST to Routes

Processing routes handle the business logic. Separate them from the REST declarations so each route has a single responsibility.

Java
@Component
public class OrderProcessingRoute extends RouteBuilder {

    @Override
    public void configure() {

        from("direct:getAllOrders")
            .bean(OrderService.class, "findAll")
            .log("Returning ${body.size} orders");

        from("direct:createOrder")
            .log("Creating order: ${body}")
            .bean(OrderService.class, "save")
            .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(201));

        from("direct:deleteOrder")
            .process(exchange -> {
                String id = exchange.getIn().getHeader("id", String.class);
                orderService.delete(id);
                exchange.getIn().setBody(null);
            })
            .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(204));
    }
}

OpenAPI / Swagger Integration

Add camel-openapi-java to auto-generate an OpenAPI 3 spec from your REST DSL definitions. Access the spec at /api/api-doc and the Swagger UI at /webjars/swagger-ui/index.html.

XML
<dependency>
    <groupId>org.apache.camel.springboot</groupId>
    <artifactId>camel-openapi-java-starter</artifactId>
</dependency>

<!-- Swagger UI -->
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>swagger-ui</artifactId>
    <version>5.11.0</version>
</dependency>
Java
restConfiguration()
    .component("servlet")
    .bindingMode(RestBindingMode.json)
    .apiContextPath("/api-doc")
    .apiContextRouteId("api-doc-route")
    .apiProperty("api.title", "Order Service API")
    .apiProperty("api.version", "1.0")
    .apiProperty("cors", "true");
Camel derives the OpenAPI schema from the type(), outType(), and param() declarations on each REST verb. The more detail you provide, the richer the generated spec.

REST Configuration Options

Key restConfiguration() options to know when deploying to different environments.

Java
restConfiguration()
    .component("servlet")          // servlet | netty-http | undertow | jetty
    .scheme("https")               // http or https
    .host("0.0.0.0")
    .port(8443)
    .contextPath("/api")
    .bindingMode(RestBindingMode.json)
    // Enable CORS for browser clients
    .enableCORS(true)
    .corsHeaderProperty("Access-Control-Allow-Origin", "*")
    // JSON formatting
    .dataFormatProperty("prettyPrint", "true")
    // OpenAPI spec endpoint
    .apiContextPath("/api-doc")
    .apiProperty("api.title", "My API")
    .apiProperty("api.version", "1.0");
Do not set enableCORS(true) with a wildcard origin (*) in production. Restrict to specific origins using corsHeaderProperty("Access-Control-Allow-Origin", "https://yourdomain.com").