标准规范 (Standards)
你当前正在浏览历史版本 Vert.x 4.4.9 的文档。 访问本页面的 最新版本。

Vert.x OpenAPI 契约引擎 (vertx-openapi)

Preview

Vert.x OpenAPI 扩展为 Vert.x 提供了针对 OpenAPI 3(支持 3.0 与 3.1 版本)规范的响应式契约驱动开发能力。

Vert.x OpenAPI 能够:

  • 解析并严格校验 OpenAPI 契约定义。

  • 依据 OpenAPI 契约解析并校验入站 HTTP 请求。

  • 依据 OpenAPI 契约解析并校验出站 HTTP 响应。

引入依赖

要在项目中使用 Vert.x OpenAPI,请在构建描述文件中添加以下依赖:

  • Maven(在 pom.xml 中):

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-openapi</artifactId>
  <version>5.0.12</version>
</dependency>
  • Gradle(在 build.gradle 文件中):

dependencies {
  compile 'io.vertx:vertx-openapi:5.0.12'
}

OpenAPIContract 契约对象

使用 Vert.x OpenAPI 时,第一步总是从你的 API 契约文件中异步构建 OpenAPIContract 实例:

String pathToContract = "../../myContract.json"; // 支持 JSON 或 YAML 格式
Future<OpenAPIContract> contract = OpenAPIContract.from(vertx, pathToContract);
出于安全防护考量,本库不会主动从公网下载契约引用的外部 URL 资源。若契约包含外部引用,必须预先拉取至本地并通过参数一并注册至 OpenAPIContract。

以下示例展示了契约包含外部引用时的加载方式:

paths:
  /pets:
    get:
      operationId: listPets
      parameters:
        - name: query
          schema:
            $ref: 'https://example.com/pet-components#/components/schemas/Query'
String pathToContract = "../../myContract.json";
String pathToComponents = "../../myComponents.json";
Map<String, String> additionalContractFiles = new HashMap<>();
additionalContractFiles.put("https://example.com/pet-components", pathToComponents);

Future<OpenAPIContract> contract =
  OpenAPIContract.from(vertx, pathToContract, additionalContractFiles);
在实例化 OpenAPIContract 期间,框架会对契约本身执行格式校验;若契约违反 OpenAPI 规范或使用了尚未支持的高级特性,将抛出异常拦截。

遍历 Path、Operation 与 Parameter

OpenAPIContract 提供了便捷的方法遍历契约中的路径(Path)、操作(Operation)及参数(Parameter)元数据:

OpenAPIContract contract = getContract();

for (Path path : contract.getPaths()) {
  for (Parameter pathParameter : path.getParameters()) {
    // 读取参数对象的元数据
    pathParameter.isRequired();
    pathParameter.getSchema();
  }
  for (Operation operation : path.getOperations()) {
    // 读取操作对象的元数据
    operation.getOperationId();
    operation.getRequestBody();
    operation.getParameters();
  }
}

厂商扩展指令 (Extensions)

Vert.x OpenAPI 支持自定义扩展属性 x-vertx-openapi-urldecode,用以指定 cookie 或 header 参数在解析时是否需要执行 URL 解码(默认值为 false;而 query 与 path 参数始终会自动解码):

paths:
  /forceEncoding:
    get:
      operationId: forceEncoding
      parameters:
        - in: header
          name: headerWithEncodedContent
          x-vertx-openapi-urldecode: true
          schema:
            type: string

入站请求合法性校验

RequestValidator 提供了丰富的 validate 方法来严密校验到来的 HTTP 请求:

OpenAPIContract contract = getContract();
RequestValidator validator = RequestValidator.create(vertx, contract);

vertx.createHttpServer().requestHandler(httpServerRequest -> {
  // 显式传入 operationId 可以避免系统重复计算当前路由,性能更优:
  validator.validate(httpServerRequest, "yourOperationId")
    .onSuccess(validatedRequest -> {
      // 获取校验合法的请求体与标头
      Buffer body = validatedRequest.getBody();
      MultiMap headers = validatedRequest.getHeaders();
    });
}).listen(0);

出站响应合法性校验

ResponseValidator 用于在服务返回前校验出站响应数据是否符合 OpenAPI 契约规范。校验通过后返回的 ValidatedResponse 可直接安全发送给客户端:

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

JsonObject cat = new JsonObject().put("name", "foo");
ValidatableResponse response =
  ValidatableResponse.create(200, cat.toBuffer(), APPLICATION_JSON.toString());

vertx.createHttpServer().requestHandler(httpServerRequest -> {
  validator.validate(response, "yourOperationId")
    .onSuccess(validatedResponse -> {
      // 响应数据符合契约,直接下发给客户端:
      validatedResponse.send(httpServerRequest.response());
    });
});

异常处理与错误诊断

若请求或响应未通过校验,系统将抛出 ValidatorException。 当由于数据内容不符合声明的 JSON Schema 时,将抛出其子类 SchemaValidationException,你可以通过该异常提取关联的 OutputUnit 进行细粒度根因分析。