<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>
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
中)
-
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
接收两个可选的查询参数作为输入:from
和 to
。PUT /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
中提取 from
和 to
参数(如果存在)。在 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.completedWithJson
或 ServiceResponse.completedWithPlainText
。
例如,TransactionService#getTransactionsList
的实现如下所示:
resultHandler.handle(
Future.succeededFuture(
ServiceResponse.completedWithJson(new JsonArray())
)
);
或者当它失败时:
resultHandler.handle(
Future.failedFuture(
new HttpException(555, "Something bad happened")
)
);
ServiceRequest 数据对象
ServiceRequest
是 RoutingContext
的一个可序列化版本,但它不包含 RoutingContext
的所有数据。它会传输到您的服务:
-
getHeaders
:请求头 -
getParams
:包含routingContext.get("parsedParameters")
-
getUser
:包含routingContext.user().principal()
,如果未认证用户则为 null -
getExtra
:包含一个可配置的额外负载
您可以使用 extraPayloadMapper
配置一个构建额外负载的 lambda 表达式。
暴露您的 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