Vert.x Web API 服务

已弃用

Vert.x Web API 服务可帮助您使用 Vert.x 事件总线处理 HTTP 请求。

事件总线提供了负载均衡和在不同 Vert.x 实例之间分发请求等重要功能。我们建议您查阅事件总线文档以获取更多信息。

此模块使您能够创建 Web API 服务,这是一个基于与Vert.x 服务代理相同概念的事件总线消息消费者。然后它提供了一个处理程序来将请求代理到这些服务。

使用 Vert.x API 服务

要使用 Vert.x API 服务,请将以下依赖项添加到您的构建描述符的 dependencies 部分

  • Maven(在您的 pom.xml 中)

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-codegen</artifactId>
  <version>5.0.1</version>
  <classifier>processor</classifier>
</dependency>
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-web-api-service</artifactId>
  <version>5.0.1</version>
</dependency>
  • Gradle < 5(在您的 build.gradle 文件中)

dependencies {
  compile 'io.vertx:vertx-codegen:5.0.1:processor'
  compile 'io.vertx:vertx-web-api-service:5.0.1'
}
  • Gradle >= 5(在您的 build.gradle 文件中)

dependencies {
  annotationProcessor 'io.vertx:vertx-codegen:5.0.1:processor'
  annotationProcessor 'io.vertx:vertx-web-api-service:5.0.1'
  compile 'io.vertx:vertx-web-api-service:5.0.1'
}

您需要导入 vertx-codegen 来触发注解接口的代码生成。如果您只需要 RouteToEBServiceHandler,则不需要它。

如果您想在不同语言中使用您编写的接口,则需要添加相应的语言依赖项,例如 Groovy 的 vertx-lang-groovy

将 HTTP 请求代理到 Web API 服务

要将请求代理到事件总线,您可以使用 RouteToEBServiceHandler。此处理程序将从 RoutingContext 中提取的一些数据放入 ServiceRequest 中发送,并期望收到 ServiceResponse 作为回复。

router
  .get("/hello")
  .handler(validationHandler)
  .handler(
    RouteToEBServiceHandler
      .build(eventBus, "greeters.myapplication", "hello")
  );

您还可以定义每次通过事件总线发送消息时将使用的 DeliveryOptions

router
  .get("/hello")
  .handler(validationHandler)
  .handler(
    RouteToEBServiceHandler
      .build(eventBus, "greeters.myapplication", "hello",
        new DeliveryOptions().setSendTimeout(1000))
  );
在挂载 RouteToEBServiceHandler 之前,您必须挂载一个 ValidationHandler 来提取请求参数。否则,将不会发送任何请求参数。

定义您的 Web API 服务接口

我们建议您在继续之前阅读服务代理文档

假设我们已在 Router 中定义了两个不同的路由,如下所示:

router.get("/api/transactions")
  .handler(
    ValidationHandlerBuilder.create(repository)
      .queryParameter(optionalParam("from", stringSchema()))
      .queryParameter(optionalParam("to", stringSchema()))
      .build()
  ).handler(
    RouteToEBServiceHandler.build(eventBus, "transactions.myapplication",
      "getTransactionsList")
  );
router.post("/api/transactions")
  .handler(
    ValidationHandlerBuilder.create(repository)
      .body(json(objectSchema()))
      .build()
  ).handler(
    RouteToEBServiceHandler.build(eventBus, "transactions.myapplication",
      "putTransaction")
  );

GET /api/transactions 接收两个可选的查询参数作为输入:fromtoPUT /api/transactions 接收一个 JsonObject 作为请求体。

现在我们可以构建处理这些端点的 TransactionService 接口。对于每个端点,您需要编写一个方法,其名称与构建 RouteToEBServiceHandler 时指定的 action 对应。方法参数需要遵循以下几条规则:

  • 最后一个参数必须是 Handler<AsyncResult<ServiceResponse>> 类型。

  • 倒数第二个参数必须是 ServiceRequest 类型。

  • 从第一个参数到倒数第二个参数(不包括)的所有参数都将从 RequestParameters 中自动提取,并具有指定的类型,但它们需要遵守服务代理限制

请求参数仅由方法参数的名称标识,并且特殊的 body 方法参数名称用于提取请求体。

例如

@WebApiServiceGen
interface TransactionService {
  void getTransactionsList(String from, String to, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
  void putTransaction(JsonObject body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
}

当您在 TransactionService#getTransactionsList 接收请求时,生成的服务处理程序将自动从 ServiceRequest 中提取 fromto 参数(如果存在)。在 TransactionService#putTransaction 中,我们使用 body 参数名称来提取 JSON 体。

服务处理程序还能够自动将 JsonObject 转换为 Vert.x 数据对象,例如,如果您有一个与上述 JSON Schema 匹配的 Transaction 数据对象,您可以将 putTransaction 签名重写为:

void putTransaction(Transaction body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);

您还可以使用 RequestParameter 来提取参数,例如:

void putTransaction(RequestParameter body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);

我们建议使用 RequestParameter 类型来提取使用 JSON Schema allOf/anyOf/oneOf/not 关键字的参数,因为提取可能会产生未定义的行为。

使用 DataObjects 时,默认情况下 base64 字符串使用 base64url 字母表处理,而 OpenAPI 没有强制要求此字母表,因此它假定为 basic。要强制 DataObject 使用特定字母表,可以在 @DataObject 注解中进行配置。

实现您的 Web API 服务

现在您可以实现您的服务。请记住,ServiceRequest 对象包含请求头和参数映射。

要写入请求,您必须使用 ServiceResponse 调用 resultHandler。要创建 ServiceResponse 实例,您可以使用一些便捷方法,例如 ServiceResponse.completedWithJsonServiceResponse.completedWithPlainText

例如,TransactionService#getTransactionsList 的实现如下所示:

resultHandler.handle(
  Future.succeededFuture(
    ServiceResponse.completedWithJson(new JsonArray())
  )
);

或者当它失败时:

resultHandler.handle(
  Future.failedFuture(
    new HttpException(555, "Something bad happened")
  )
);

ServiceRequest 数据对象

ServiceRequestRoutingContext 的一个可序列化版本,但它不包含 RoutingContext 的所有数据。它会传输到您的服务:

  • getHeaders:请求头

  • getParams:包含 routingContext.get("parsedParameters")

  • getUser:包含 routingContext.user().principal(),如果未认证用户则为 null

  • getExtra:包含一个可配置的额外负载

您可以使用 extraPayloadMapper 配置一个构建额外负载的 lambda 表达式。

ServiceResponse 数据对象

ServiceResponse 由以下部分组成:

  • 响应头

  • 状态码/状态消息

  • 作为负载的响应体。如果您不设置负载或将其设置为 null,将不会发送任何响应体。

暴露您的 Web API 服务

现在您可以将您的服务注册到事件总线。

TransactionService transactionService = new TransactionServiceImpl();

// Mount the service on the event bus
ServiceBinder transactionServiceBinder = new ServiceBinder(vertx);
transactionServiceBinder
  .setAddress("transactions.myapplication")
  .register(TransactionService.class, transactionService);

有关如何暴露服务的更多信息,请查阅Vert.x 服务代理文档

OpenAPI 集成

Vert.x Web API 服务提供了一个 OpenAPIRouterHandler,可以将其添加到 OpenAPIRoute 中,并将传入的 HTTP 请求转发到相关的 Web API 服务代理。此 OpenAPIRoute 的验证必须启用。

OpenAPIContract contract = getContract();
ResponseValidator responseValidator = ResponseValidator.create(vertx, contract);

OpenAPIRoute route = routerBuilder.getRoute("getPets");
OpenAPIRouterHandler handler = OpenAPIRouterHandler.create(vertx,
  route.getOperation(), responseValidator);

route.addHandler(handler);

OpenAPI 契约扩展

OpenAPIRouterHandler 添加到 OpenAPIRoute 需要使用 x-vertx-event-bus 扩展来扩展相关的 OpenAPI 操作。x-vertx-event-bus 扩展必须填充相关 Web API 服务代理的地址和方法名称。如果未定义方法名称,则将使用 operationId

# without method name
paths:
  /pets:
    get:
      operationId: listPets
      x-vertx-event-bus: myEventbusAddress

# with method name
paths:
  /pets:
    get:
      operationId: listPets
      x-vertx-event-bus:
        address: myEventbusAddress
        method: getPetById

# defined on Path level for all operations
paths:
  /pets:
    x-vertx-event-bus: myEventbusAddress
    get:
      operationId: listPets
    post:
      operationId: createPet