Camel REST DSL이란?
Camel은 REST 서버를 구축하기 위한 REST DSL을 제공합니다. Undertow, Jetty, Servlet 등 여러 HTTP 서버 중 원하는 것을 선택하고, 동일한 DSL 문법으로 REST API를 정의할 수 있습니다. Spring MVC나 JAX-RS 대신 Camel을 선택하면 REST 엔드포인트에서 복잡한 통합 로직을 자연스럽게 표현할 수 있습니다.
REST DSL 기본 구조
public class OrderRestRoutes extends RouteBuilder {
@Override
public void configure() throws Exception {
// REST 설정
restConfiguration()
.component("undertow")
.host("0.0.0.0")
.port(8080)
.bindingMode(RestBindingMode.json); // 자동 JSON 직렬화
// REST 엔드포인트 정의
rest("/orders")
.get("/").to("direct:listOrders")
.get("/{id}").to("direct:getOrder")
.post("/").type(OrderDto.class).to("direct:createOrder")
.put("/{id}").type(OrderDto.class).to("direct:updateOrder")
.delete("/{id}").to("direct:deleteOrder");
// 실제 처리 라우트
from("direct:listOrders")
.to("bean:orderService?method=findAll");
from("direct:getOrder")
.to("bean:orderService?method=findById(${header.id})");
from("direct:createOrder")
.to("bean:orderService?method=create");
}
}
Path Parameter와 Query Parameter 처리
REST 경로의 변수는 헤더로, 쿼리 파라미터는 헤더나 직접 접근으로 처리합니다.
rest("/products")
.get("/{category}?page={page}&size={size}")
.to("direct:searchProducts");
from("direct:searchProducts")
.process(exchange -> {
String category = exchange.getIn().getHeader("category", String.class);
int page = exchange.getIn().getHeader("page", 0, Integer.class);
int size = exchange.getIn().getHeader("size", 10, Integer.class);
// 서비스 호출
});
JSON 자동 바인딩
bindingMode(RestBindingMode.json)를 설정하면 Camel이 자동으로 JSON ↔ Java 객체 변환을 처리합니다. Jackson이 기본 변환기로 사용됩니다.
rest("/orders")
.post("/")
.type(OrderDto.class) // 요청 역직렬화 타입
.outType(OrderResponse.class) // 응답 직렬화 타입
.to("direct:createOrder");
from("direct:createOrder")
.process(exchange -> {
OrderDto dto = exchange.getIn().getBody(OrderDto.class); // 자동 변환됨
OrderResponse response = orderService.create(dto);
exchange.getIn().setBody(response); // 자동으로 JSON 응답
});
Swagger/OpenAPI 문서 자동 생성
camel-swagger-java 의존성을 추가하면 REST DSL 정의를 기반으로 Swagger UI와 OpenAPI 스펙을 자동 생성합니다.
restConfiguration()
.component("undertow")
.port(8080)
.enableCORS(true)
.dataFormatProperty("prettyPrint", "true")
.contextPath("/api")
.apiContextPath("/api-doc") // Swagger JSON 경로
.apiProperty("api.title", "Order API")
.apiProperty("api.version", "1.0.0");
http://localhost:8080/api-doc에서 OpenAPI JSON을, Swagger UI 경로에서 인터랙티브 문서를 확인할 수 있습니다.
에러 응답 처리
onException(NotFoundException.class)
.handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(404))
.setBody(simple("{"error": "리소스를 찾을 수 없습니다"}"));
onException(ValidationException.class)
.handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400))
.setBody(simple("{"error": "${exception.message}"}"));