4.2. 使用 REST DSL 定义服务


REST DSL 是一个 facade

REST DSL 有效地是一个 传真,它为在 Java DSL 或 XML DSL (域特定语言)中定义 REST 服务提供了简化的语法。REST DSL 不实际提供 REST 实施,它只是围绕 现有 REST 实施(在 Apache Camel 中有多个)的包装程序。

REST DSL 的优点

REST DSL 打包程序层提供以下优点:

  • 现代易用的语法,用于定义 REST 服务。
  • 与多个不同的 Apache Camel 组件兼容。
  • OpenAPI 集成(通过 camel-openapi-java 组件)。

与 REST DSL 集成的组件

由于 REST DSL 不是实际的 REST 实施,因此您需要做的第一件事是选择 Camel 组件以提供底层实施。以下 Camel 组件目前与 REST DSL 集成:

注意

Rest 组件( camel-core的一部分)不是 REST 实施。与 REST DSL 一样,Rest 组件是一个灰色的,提供简化的语法来使用 URI 语法定义 REST 服务。Rest 组件还需要底层 REST 实施。

配置 REST DSL 以使用 REST 实现

要指定 REST 实施,您可以使用 restConfiguration () 构建器(在 Java DSL 中)或 restConfiguration 元素(在 XML DSL 中)。例如,要将 REST DSL 配置为使用 Spark-Rest 组件,您可以使用类似 Java DSL 中的 builder 表达式:

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

在 XML DSL 中使用类似如下的元素(作为 camelContext的子级):

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

语法

定义 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 路径片段的一个或多个 verb 子句。HTTP 动词可以是 get ()head ()put ()post ()delete ()patch ()verb () 之一。每个 verb 子句都可以使用以下任何一种语法:

  • 动词子句以 to () 关键字结尾。例如:

    get("...").Option()+.to("...")
  • verb 子句以 route () 关键字结尾(用于嵌入 Camel 路由)。例如:

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

带有 Java 的 REST DSL

在 Java 中,若要使用 REST DSL 定义服务,请将 REST 定义放在 RouteBuilder.configure () 方法的正文中,就像您对常规 Apache Camel 路由一样。例如,要使用带有 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 DSL 以使用特定的 REST 实施(Spark-Rest)。
rest()
使用 REST DSL 定义服务。每个 verb 子句都由一个 to () 关键字终止,它将传入的消息转发到 直接 端点(同一应用中 直接 组件路由)。
from()
定义常规 Camel 路由。

带有 XML 的 REST DSL

在 XML 中,要使用 XML DSL 定义服务,请将 rest 元素定义为 camelContext 元素的子元素。例如,要使用带有 Spark-Rest 组件的 REST DSL 定义一个简单的 Hello World 服务,请定义以下 XML 代码(在 Blueprint 中):

<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>

指定基本路径

rest () 关键字(Java DSL)或 rest 元素的 path 属性(XML DSL)允许您定义一个基本路径,然后作为所有 verb 子句的路径作为前缀。例如,给定以下 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

基本路径是可选的。如果您愿意,可以(不完美)在每个 verb 子句中指定完整路径:

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

使用动态功能

REST DSL 支持 toD 动态 to 参数。使用此参数指定 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 dynamic to 参数的详情,请参考 “动态到”一节

URI 模板

在 verb 参数中,您可以指定一个 URI 模板,它可让您捕获指定属性中的特定路径片段(然后映射到 Camel 消息标头)。例如,如果要对 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 结尾的 GET HTTP Request 来调用该服务,HTTP 响应是 Hello Joe

嵌入式路由语法

您可以使用 route () 关键字(Java DSL)或 to element (XML DSL)终止 verb 子句,而是使用 route ()关键字(Java DSL)或 route 元素(XML DSL)直接嵌入 Apache Camel 路由。route () 关键字可让您使用以下语法将路由嵌入到 verb 子句中:

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

其中 endRest () 关键字(Java DSL)是一个必要的标点标记,可让您分隔 verb 子句(当 rest () 构建器中有多个 verb 子句)。

例如,您可以重构 Hello World 示例以使用嵌入式 Camel 路由,如 Java DSL 所示:

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 中定义任何异常子句(使用 Exception ())或拦截器(使用 intercept ()),则这些 exception 子句和拦截器也在嵌入的路由中处于活跃状态。

REST DSL 和 HTTP 传输组件

如果您没有显式配置 HTTP 传输组件,则 REST DSL 会通过检查 classpath 上的可用组件来自动发现要使用的 HTTP 组件。REST DSL 查找任何 HTTP 组件的默认名称,并使用它找到的第一个名称。如果 classpath 上没有 HTTP 组件,且您没有明确配置 HTTP 传输,则默认的 HTTP 组件为 camel-http

指定请求和响应的内容类型

您可以使用 Java 中的 consumes () 和 generate () 选项过滤 HTTP 请求和响应 的内容类型,或者在 XML 中生成 属性。例如,一些通用内容类型(官方称为 互联网介质类型)如下:

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

内容类型被指定为 REST DSL 中 verb 子句上的选项。例如,要将 verb 子句限制为仅接受 text/plain HTTP 请求,并且仅发送 文本/html HTTP 响应,您可以使用类似如下的 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>

您还可以指定要以逗号分隔的列表 形式使用 () generate ()的参数。例如,使用("text/plain, application/json")

其他 HTTP 方法

有些 HTTP 服务器实现支持额外的 HTTP 方法,它们不是由 REST DSL, get (), head (), put (), post (), delete (), patch () 的标准集合提供。要访问额外的 HTTP 方法,您可以在 Java DSL 中使用 generic 关键字 verb (),并在 XML DSL 中使用 generic 元素 verb

例如,要在 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>

定义自定义 HTTP 错误消息

如果您的 REST 服务需要发送错误消息作为其响应,您可以定义一个自定义 HTTP 错误消息:

  1. 通过将 Exchange.HTTP_RESPONSE_CODE 标头键设置为错误代码值(如 400404 等等)来指定 HTTP 错误代码。此设置指示您要发送错误消息回复的 REST DSL,而不是常规响应。
  2. 使用自定义错误消息填充消息正文。
  3. 如果需要,设置 Content-Type 标头。
  4. 如果您的 REST 服务被配置为 marshal 到 Java 对象(已启用 bindingMode ),您应该确保启用了 skipBindingOnErrorCode 选项(默认为 )。这是为了确保 REST DSL 在发送响应时不会尝试 unmarshal 消息正文。

    有关对象绑定的详情,请参阅 第 4.3 节 “到 Java 对象和从 Java 对象进行复制”

以下 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 bean,其实现如下:

// 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 bean 中,我们定义自定义错误消息,并将 HTTP 错误代码设置为 400

参数默认值

可以为传入 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");

在自定义 HTTP 错误消息中嵌套 JsonParserException

您可能要返回自定义错误消息的一个常见情况是以打包 JsonParserException 异常。例如,您可以方便地利用 Camel 异常处理机制创建自定义 HTTP 错误消息,以及 HTTP 错误代码 400,如下所示:

// 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");

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");

在这种情况下,指定的选项适用于所有下级动词。或者选项可应用于每个单独的 verb 子句,如下所示:

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");

在这种情况下,指定的选项只适用于相关的 verb 子句,覆盖基础部分中的任何设置。

表 4.1 “REST DSL 选项” 总结了 REST DSL 支持的选项。

表 4.1. REST DSL 选项
Java DSLXML DSL描述

bindingMode()

@bindingMode

指定绑定模式,可用于将传入消息发送到 Java 对象(以及可选的 unmarshal Java 对象到传出消息)。可以有以下值: off (默认)、autojsonxmljson_xml

consumes ()

@consumes

将 verb 子句限制为仅接受 HTTP Request 中指定的互联网介质类型(MIME 类型)。典型值有: text/plain,text/http,text/xml,application/json,application/xml.

customId()

@customId

定义用于 JMX 管理的自定义 ID。

description()

description

记录 REST 服务或 verb 子句。适用于 JMX 管理和工具。

enableCORS()

@enableCORS

如果为 true,请在 HTTP 响应中启用 CORS (跨原始资源共享)标头。默认为 false

id()

@id

为 REST 服务定义唯一 ID,这对于为 JMX 管理和其他工具定义非常有用。

method ()

@method

指定此 verb 子句处理的 HTTP 方法。通常与 generic verb () 关键字一起使用。

outType()

@outType

启用对象绑定(即启用 bindingMode 选项时),此选项指定代表 HTTP Response 消息的 Java 类型。

produces ()

生成

将 verb 子句限制为仅在 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)或 rest 元素(XML DSL)的基本路径。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.