4.2. REST DSL을 사용하여 서비스 정의

4.2.1. REST DSL은 facade입니다.

REST DSL은 효과적으로 Java DSL 또는 XML DSL(Domain Specific Language)에서 REST 서비스를 정의하기 위한 간소화된 구문을 제공하는 facade 입니다. REST DSL은 실제로 REST 구현을 제공하지 않으며, 기존 REST 구현에 대한 래퍼일 뿐입니다(Apache Camel에 여러 가지가 있음).

4.2.2. REST DSL의 이점

REST DSL 래퍼 계층은 다음과 같은 이점을 제공합니다.

  • REST 서비스를 정의하는 데 사용하기 쉬운 최신 구문입니다.
  • 여러 다른 Apache Camel 구성 요소와 호환됩니다.
  • OpenAPI 통합( camel-openapi-java 구성 요소를 통해).

4.2.3. REST DSL과 통합되는 구성 요소

REST DSL은 실제 REST 구현이 아니므로 가장 먼저 수행해야 하는 작업 중 하나는 기본 구현을 제공하기 위해 Camel 구성 요소를 선택하는 것입니다. 현재 다음 Camel 구성 요소가 REST DSL과 통합되어 있습니다.

참고

Rest 구성 요소( camel-core의 일부)는 REST 구현이 아닙니다. REST DSL과 마찬가지로 Rest 구성 요소는 facade이므로 URI 구문을 사용하여 REST 서비스를 정의하는 간단한 구문을 제공합니다. Rest 구성 요소에는 기본 REST 구현도 필요합니다.

4.2.4. REST 구현을 사용하도록 REST DSL 구성

REST 구현을 지정하려면 restConfiguration() 빌더(Java DSL) 또는 restConfiguration 요소( XML DSL)를 사용합니다. 예를 들어 Spark-Rest 구성 요소를 사용하도록 REST DSL을 구성하려면 Java DSL에서 다음과 같은 빌더 표현식을 사용합니다.

restConfiguration().component("spark-rest").port(9091);

XML DSL에서 다음과 같은 요소를 사용합니다( camelContext의 자식으로).

<restConfiguration component="spark-rest" port="9091"/>

4.2.5. 구문

REST 서비스를 정의하는 Java DSL 구문은 다음과 같습니다.

rest("BasePath").Option().
    .Verb("Path").Option().[to() | route().CamelRoute.endRest()]
    .Verb("Path").Option().[to() | route().CamelRoute.endRest()]
    ...
    .Verb("Path").Option().[to() | route().CamelRoute];

CamelRoute 는 선택적 임베디드 Camel 경로입니다(라이스에 표준 Java DSL 구문을 사용하여 정의됨).

REST 서비스 정의는 rest() 키워드로 시작한 다음 특정 URL 경로 세그먼트를 처리하는 하나 이상의 동사 절을 사용합니다. HTTP 동사는 get(), head(), put(), post(), delete(), patch() 또는 verb() 중 하나일 수 있습니다. 각 verb 절은 다음 구문 중 하나를 사용할 수 있습니다.

  • 동사 절은 () 키워드로 끝납니다. 예를 들면 다음과 같습니다.

    get("...").Option()+.to("...")
  • route() 키워드로 끝나는 동사 절( Camel 경로 포함용). 예를 들면 다음과 같습니다.

    get("...").Option()+.route("...").CamelRoute.endRest()

4.2.6. Java를 사용한 REST DSL

Java에서 REST DSL을 사용하여 서비스를 정의하려면 일반 Apache Camel 경로와 마찬가지로 RouteBuilder.configure() 메서드 본문에 REST 정의를 배치합니다. 예를 들어, Spark-Rest 구성 요소와 함께 REST DSL을 사용하여 간단한 Hello World 서비스를 정의하려면 다음 Java 코드를 정의합니다.

restConfiguration().component("spark-rest").port(9091);

rest("/say")
    .get("/hello").to("direct:hello")
    .get("/bye").to("direct:bye");

from("direct:hello")
    .transform().constant("Hello World");
from("direct:bye")
    .transform().constant("Bye World");

이전 예제에서는 세 가지 종류의 빌더를 제공합니다.

restConfiguration()
특정 REST 구현(Spark-Rest)을 사용하도록 REST DSL을 구성합니다.
rest()
REST DSL을 사용하여 서비스를 정의합니다. 각 verb 절은 들어오는 메시지를 직접 엔드포인트로 전달하는 to() 키워드로 종료됩니다( 직접 구성 요소는 동일한 애플리케이션 내에서 경로를 함께 분할).
from()
일반 Camel 경로를 정의합니다.

4.2.7. XML이 있는 REST DSL

XML에서 XML DSL을 사용하여 서비스를 정의하려면 rest 요소를 camelContext 요소의 자식으로 정의합니다. 예를 들어, Spark-Rest 구성 요소와 함께 REST DSL을 사용하여 간단한 Hello World 서비스를 정의하려면 다음 XML 코드( 블루프린트에서)를 정의합니다.

<camelContext xmlns="http://camel.apache.org/schema/blueprint">
  <restConfiguration component="spark-rest" port="9091"/>

  <rest path="/say">
    <get uri="/hello">
      <to uri="direct:hello"/>
    </get>
    <get uri="/bye">
      <to uri="direct:bye"/>
    </get>
  </rest>

  <route>
    <from uri="direct:hello"/>
    <transform>
      <constant>Hello World</constant>
    </transform>
  </route>
  <route>
    <from uri="direct:bye"/>
    <transform>
      <constant>Bye World</constant>
    </transform>
  </route>
</camelContext>

4.2.8. 기본 경로 지정

rest() 키워드(Java DSL) 또는 rest 요소의 path 속성( XML DSL)을 사용하면 기본 경로를 정의할 수 있으며, 기본 경로 앞에 모든 동사 절이 추가됩니다. 예를 들어 다음 Java DSL 조각이 제공됩니다.

rest("/say")
    .get("/hello").to("direct:hello")
    .get("/bye").to("direct:bye");

또는 다음 XML DSL 조각이 제공됩니다.

<rest path="/say">
  <get uri="/hello">
    <to uri="direct:hello"/>
  </get>
  <get uri="/bye" consumes="application/json">
    <to uri="direct:bye"/>
  </get>
</rest>

REST DSL 빌더는 다음과 같은 URL 매핑을 제공합니다.

/say/hello
/say/bye

기본 경로는 선택 사항입니다. 원하는 경우 각 동사 절에 전체 경로를 지정할 수 있습니다.

rest()
    .get("/say/hello").to("direct:hello")
    .get("/say/bye").to("direct:bye");

4.2.9. 동적 대상 사용

REST DSL은 toD 동적 매개 변수를 지원합니다. 이 매개변수를 사용하여 URI를 지정합니다.

예를 들어 JMS에서 동적 엔드포인트 URI는 다음과 같은 방식으로 정의할 수 있습니다.

public void configure() throws Exception {
   rest("/say")
     .get("/hello/{language}").toD("jms:queue:hello-${header.language}");
}

XML DSL에서 다음과 같은 세부 정보가 표시됩니다.

<rest uri="/say">
  <get uri="/hello//{language}">
    <toD uri="jms:queue:hello-${header.language}"/>
  </get>
<rest>

toD 동적 매개 변수에 대한 자세한 내용은 “동적 대상” 을 참조하십시오.

4.2.10. URI 템플릿

동사 인수에서는 이름이 지정된 속성( Camel 메시지 헤더에 매핑됨)에서 특정 경로 세그먼트를 캡처할 수 있는 URI 템플릿을 지정할 수 있습니다. 예를 들어 Hello World 애플리케이션을 이름별로 호출하도록 사용자 지정하려는 경우 다음과 같은 REST 서비스를 정의할 수 있습니다.

rest("/say")
    .get("/hello/{name}").to("direct:hello")
    .get("/bye/{name}").to("direct:bye");

from("direct:hello")
    .transform().simple("Hello ${header.name}");
from("direct:bye")
    .transform().simple("Bye ${header.name}");

URI 템플릿은 {name} 경로 세그먼트의 텍스트를 캡처하고 이 캡처된 텍스트를 이름 메시지 헤더에 복사합니다. /say/hello/Joe 로 끝나는 URL로 GET HTTP 요청을 전송하여 서비스를 호출하면 HTTP 응답은 Hello ctlplane 입니다.

4.2.11. 포함된 경로 구문

to() 키워드(Java DSL) 또는 to 요소( XML DSL)로 verb 절을 종료하는 대신 route() 키워드(Java DSL) 또는 경로 요소( XML DSL)를 사용하여 Apache Camel 경로를 REST DSL에 직접 포함할 수 있습니다. route() 키워드를 사용하면 다음 구문을 사용하여 동사 절에 경로를 포함할 수 있습니다.

RESTVerbClause.route("...").CamelRoute.endRest()

여기서 endRest() 키워드(Java DSL만 해당)는 동사 절을 분리할 수 있는 필수 문장 부호입니다( rest() 빌더에 두 개 이상의 동사 절이 있는 경우).

예를 들어 Java DSL에서 다음과 같이 포함된 Camel 경로를 사용하도록 Hello World 예제를 리팩터링할 수 있습니다.

rest("/say")
    .get("/hello").route().transform().constant("Hello World").endRest()
    .get("/bye").route().transform().constant("Bye World");

XML DSL의 예는 다음과 같습니다.

<camelContext xmlns="http://camel.apache.org/schema/blueprint">
  ...
  <rest path="/say">
    <get uri="/hello">
      <route>
        <transform>
          <constant>Hello World</constant>
        </transform>
      </route>
    </get>
    <get uri="/bye">
      <route>
        <transform>
          <constant>Bye World</constant>
        </transform>
      </route>
    </get>
  </rest>
</camelContext>
참고

현재 CamelContext 에서 예외 절( onException()) 또는 인터셉터( intercept()사용)를 정의하는 경우 이러한 exception 절과 인터셉터도 포함된 경로에서 활성화됩니다.

4.2.12. REST DSL 및 HTTP 전송 구성 요소

HTTP 전송 구성 요소를 명시적으로 구성하지 않으면 REST DSL은 classpath에서 사용 가능한 구성 요소를 확인하여 사용할 HTTP 구성 요소를 자동으로 검색합니다. REST DSL은 모든 HTTP 구성 요소의 기본 이름을 찾고 찾은 첫 번째 구성 요소를 사용합니다. classpath에 HTTP 구성 요소가 없고 HTTP 전송을 명시적으로 구성하지 않은 경우 기본 HTTP 구성 요소는 camel-http 입니다.

4.2.13. 요청 및 응답의 콘텐츠 유형 지정

consumes() 를 사용하여 HTTP 요청 및 응답의 콘텐츠 유형을 필터링하고 Java에서 () 옵션을 생성하거나 XML로 속성을 사용하고 생성할 수 있습니다. 예를 들어, 몇 가지 일반적인 콘텐츠 유형(알림적으로 인터넷 미디어 유형)은 다음과 같습니다.

  • text/plain
  • text/html
  • text/xml
  • application/json
  • application/xml

콘텐츠 유형은 REST DSL의 동사 절에 옵션으로 지정됩니다. 예를 들어, text/plain HTTP 요청만 수락하고 text/html HTTP 응답만 전송하도록 verb 절을 제한하려면 다음과 같은 Java 코드를 사용합니다.

rest("/email")
    .post("/to/{recipient}").consumes("text/plain").produces("text/html").to("direct:foo");

XML에서는 다음과 같이 사용 및 특성을 생성할 수 있습니다.

<camelContext xmlns="http://camel.apache.org/schema/blueprint">
  ...
  <rest path="/email">
    <post uri="/to/{recipient}" consumes="text/plain" produces="text/html">
      <to "direct:foo"/>
    </get>
  </rest>
</camelContext>

사용할 인수를 지정하거나 ( )를 쉼표 구분된 목록으로 지정할 수도 있습니다. 예를 들어 "text/plain, application/json"을 사용합니다.

4.2.14. 추가 HTTP 메서드

일부 HTTP 서버 구현은 추가 HTTP 메서드를 지원합니다. REST DSL의 표준 동사 세트인 get(), head(), put(), post(), delete(), patch(). 추가 HTTP 메서드에 액세스하려면 일반 키워드인 verb() 를 Java DSL 및 일반 요소인 verb 에서 XML DSL로 사용할 수 있습니다.

예를 들어 Java에서 TRACE HTTP 메서드를 구현하려면 다음을 수행합니다.

rest("/say")
    .verb("TRACE", "/hello").route().transform();

여기서 transform()IN 메시지의 본문을 OUT 메시지의 본문으로 복사하므로 HTTP 요청을 에코합니다.

XML에서 TRACE HTTP 메서드를 구현하려면 다음을 수행합니다.

<camelContext xmlns="http://camel.apache.org/schema/blueprint">
  ...
  <rest path="/say">
    <verb uri="/hello" method="TRACE">
      <route>
        <transform/>
      </route>
    </get>
</camelContext>

4.2.15. 사용자 정의 HTTP 오류 메시지 정의

REST 서비스에서 응답으로 오류 메시지를 보내야 하는 경우 다음과 같이 사용자 정의 HTTP 오류 메시지를 정의할 수 있습니다.

  1. Exchange.HTTP_RESPONSE_CODE 헤더 키를 오류 코드 값(예: 400,404 등)으로 설정하여 HTTP 오류 코드를 지정합니다. 이 설정은 일반 응답 대신 오류 메시지 응답을 보낼 REST DSL에 나타냅니다.
  2. 메시지 본문을 사용자 지정 오류 메시지로 채웁니다.
  3. 필요한 경우 Content-Type 헤더를 설정합니다.
  4. REST 서비스가 Java 오브젝트(즉, bindingMode 가 활성화됨)로 마샬링되도록 구성된 경우 skipBindingOnErrorCode 옵션이 활성화되어 있는지 확인해야 합니다(기본적으로). 이는 REST DSL이 응답을 전송할 때 메시지 본문을 분리하지 않도록 하기 위한 것입니다.

    오브젝트 바인딩에 대한 자세한 내용은 4.3절. “Java Objects 간에 마샬링” 을 참조하십시오.

다음 Java 예제에서는 사용자 정의 오류 메시지를 정의하는 방법을 보여줍니다.

// Java
// Configure the REST DSL, with JSON binding mode
restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.json);

// Define the service with REST DSL
rest("/users/")
    .post("lives").type(UserPojo.class).outType(CountryPojo.class)
        .route()
            .choice()
                .when().simple("${body.id} < 100")
                    .bean(new UserErrorService(), "idTooLowError")
                .otherwise()
                    .bean(new UserService(), "livesWhere");

이 예에서 입력 ID가 100보다 작으면 다음과 같이 구현된 UserErrorService pin을 사용하여 사용자 지정 오류 메시지를 반환합니다.

// Java
public class UserErrorService {
    public void idTooLowError(Exchange exchange) {
        exchange.getIn().setBody("id value is too low");
        exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "text/plain");
        exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
    }
}

UserErrorService pin에서 사용자 지정 오류 메시지를 정의하고 HTTP 오류 코드를 400 으로 설정합니다.

4.2.16. 매개변수 기본값

들어오는 Camel 메시지의 헤더에 기본값을 지정할 수 있습니다.

쿼리 매개변수에 대한 상세 정보와 같은 키워드를 사용하여 기본값을 지정할 수 있습니다. 예를 들어 아래 코드에서 기본값은 false 입니다. 즉, verbose 키가 있는 헤더에 다른 값이 제공되지 않으면 false 가 기본값으로 삽입됩니다.

rest("/customers/")
    .get("/{id}").to("direct:customerDetail")
    .get("/{id}/orders")
      .param()
	.name("verbose")
	.type(RestParamType.query)
	.defaultValue("false")
	.description("Verbose order details")
      .endParam()
        .to("direct:customerOrders")
    .post("/neworder").to("direct:customerNewOrder");

4.2.17. 사용자 지정 HTTP 오류 메시지에서 JsonParserException 래핑

사용자 지정 오류 메시지를 반환할 수 있는 일반적인 경우는 JsonParserException 예외를 래핑하기 위한 것입니다. 예를 들어 다음과 같이 Camel 예외 처리 메커니즘을 편리하게 악용하여 HTTP 오류 코드 400을 사용하여 사용자 정의 HTTP 오류 메시지를 생성할 수 있습니다.

// Java
onException(JsonParseException.class)
    .handled(true)
    .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400))
    .setHeader(Exchange.CONTENT_TYPE, constant("text/plain"))
    .setBody().constant("Invalid json data");

4.2.18. REST DSL 옵션

일반적으로 REST DSL 옵션은 다음과 같이 서비스 정의의 기본 부분(즉, 즉시 rest())에 직접 적용할 수 있습니다.

rest("/email").consumes("text/plain").produces("text/html")
    .post("/to/{recipient}").to("direct:foo")
    .get("/for/{username}").to("direct:bar");

이 경우 지정된 옵션은 모든 하위 동사 절에 적용됩니다. 또는 옵션은 다음과 같이 각 동사 절에 적용할 수 있습니다.

rest("/email")
    .post("/to/{recipient}").consumes("text/plain").produces("text/html").to("direct:foo")
    .get("/for/{username}").consumes("text/plain").produces("text/html").to("direct:bar");

지정된 옵션은 관련 동사 절에만 적용되는 경우 기본 부분의 설정을 재정의합니다.

표 4.1. “REST DSL 옵션” REST DSL에서 지원하는 옵션을 요약합니다.

표 4.1. REST DSL 옵션

Java DSLXML DSL설명

bindingMode()

@bindingMode

들어오는 메시지를 Java 오브젝트에 마샬링하는 데 사용할 수 있는 바인딩 모드를 지정합니다(선택적으로는 Java 개체를 발신 메시지에 매길 수 없음). can have the following values: off (default), auto,json,xml,json_xml.

consumes()

@consumes

동사 절은 HTTP 요청에서 지정된 인터넷 미디어 유형(MIME 유형)만 수락하도록 제한합니다. 일반적인 값은 text/plain,text/http,text/xml,application/json,application/xml 입니다.

customId()

@customId

Cryostat 관리를 위한 사용자 지정 ID를 정의합니다.

description()

description

REST 서비스 또는 동사 절을 문서화합니다. Cryostat 관리 및 툴링에 유용합니다.

enableCORS()

@enableCORS

true 인 경우 HTTP 응답에서 CORS(cross-origin resource sharing) 헤더를 활성화합니다. 기본값은 false 입니다.

id()

@id

REST 서비스의 고유 ID를 정의합니다. 이 ID는 Cryostat 관리 및 기타 툴링에 대해 정의하는 데 유용합니다.

method()

@method

이 동사 절에서 처리하는 HTTP 메서드를 지정합니다. 일반적으로 일반 동사 () 키워드와 함께 사용됩니다.

outType()

@outType

개체 바인딩이 활성화된 경우(즉, bindingMode 옵션이 활성화된 경우) 이 옵션은 HTTP 응답 메시지를 나타내는 Java 유형을 지정합니다.

produces()

생성

동사 절은 HTTP 응답에서 지정된 인터넷 미디어 유형(MIME 유형)만 생성하도록 제한합니다. 일반적인 값은 text/plain,text/http,text/xml,application/json,application/xml 입니다.

type()

@type

개체 바인딩이 활성화된 경우(즉, bindingMode 옵션이 활성화된 경우) 이 옵션은 HTTP Request 메시지를 나타내는 Java 유형을 지정합니다.

VerbURIArgument

@uri

경로 세그먼트 또는 URI 템플릿을 동사의 인수로 지정합니다. 예를 들어 get(VerbURIArgument) 입니다.

BasePathArgument

@path

rest() 키워드(Java DSL) 또는 나머지 요소( XML DSL)의 기본 경로를 지정합니다.