4.2. 使用 REST DSL 定义服务


REST DSL 是一个 facade

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

REST DSL 的优点

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

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

与 REST DSL 集成的组件

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

注意

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

配置 REST DSL 以使用 REST 实施

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

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

基本路径是可选的。如果您希望,您可以在每个动词 子句中指定完整路径:

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

使用 Dynamic To

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

在操作动词参数中,您可以指定一个 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} 路径片段的文本,并将这个捕获的文本复制到 名称 消息标头中。如果您通过发送 GET HTTP 请求并使用以 /say/hello/Joe 结尾的 URL 调用该服务,则 HTTP 响应为 Hello Joe

嵌入式路由语法

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

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

其中 endRest () 关键字(仅限 Java DSL 关键字)是必要的标点标记,使您能够分隔 verb 子句(当 rest () 构建器中有多个动词子时)。

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

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 子句和拦截器也会在嵌入式路由中活跃。

REST DSL 和 HTTP 传输组件

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

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

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

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

内容类型在 REST DSL 中的 verb 子句上作为选项指定。例如,要将 verb 子句限制为仅接受 text/plain HTTP 请求,并且仅发送 text/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>

您还可以将参数指定为 consume () 或 produce () 作为以逗号分隔的列表。例如,consume ("text/plain, application/json")

其他 HTTP 方法

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

例如,要在 Java 中实施 TRACE HTTP 方法:

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

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

    有关对象绑定的详情,请参阅 第 4.3 节 “Marshalling to and from 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 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 请求中接受指定的 Internet 介质类型(MIME 类型)。典型的值有: text/plain,text/http,text/xml,application/json,application/xml.

customId()

@customId

为 JMX 管理定义自定义 ID。

description()

description

记录 REST 服务或操作动词子句。适用于 JMX 管理和工具。

enableCORS()

@enableCORS

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

id()

@id

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

method()

@method

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

outType()

@outType

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

produces()

produces

限制 verb 子句,以仅在 HTTP 响应中生成指定的 Internet 介质类型(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.