<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.vertx.howtos</groupId>
<artifactId>web-and-openapi-howto</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<vertx.version>4.0.0</vertx.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-stack-depchain</artifactId>
<version>${vertx.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-openapi</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.5.0</version>
<configuration>
<mainClass>io.vertx.howtos.openapi.APIVerticle</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
从 OpenAPI 文档创建 Vert.x Web 路由器
本文档将向您展示如何使用 OpenAPI 文档来创建 Vert.x Web 路由器,该路由器可以验证并提取传入的请求参数。
您将构建什么
您将构建一个 Vert.x 应用程序,该应用程序管理一个内存中的宠物列表,并通过 Petstore API https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml 提供服务。
您需要什么
-
文本编辑器或 IDE
-
Java 8 或更高版本
-
Maven
创建项目
以下是您应该使用的 pom.xml
文件的内容
pom.xml
加载 OpenAPI 文档
Vert.x Web API Contract 为您提供了 RouterBuilder
,一个帮助您从 OpenAPI 规范构建 Vert.x Web 路由器的对象。
将规范加载到您的 Verticle 的启动方法中
RouterBuilder.create(this.vertx, "petstore.yaml")
.onSuccess(routerBuilder -> { (1)
// You can start building the router using routerBuilder
}).onFailure(cause -> { (2)
// Something went wrong during router factory initialization
startPromise.fail(cause);
});
1 | 如果加载成功,您将收到一个即用的 RouterBuilder 实例,否则 |
2 | Verticle 部署将失败 |
编写处理器
现在您可以使用 operation(operationId).handler()
将业务逻辑放入路由处理器中。
对于 listPets
routerBuilder.operation("listPets").handler(routingContext ->
routingContext
.response() (1)
.setStatusCode(200)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json") (2)
.end(new JsonArray(getAllPets()).encode()) (3)
);
1 | 获取响应对象 |
2 | 设置 Content-type: application/json 头 |
3 | 写入包含所有宠物的响应 |
对于 createPets
routerBuilder.operation("createPets").handler(routingContext -> {
RequestParameters params = routingContext.get(ValidationHandler.REQUEST_CONTEXT_KEY); (1)
JsonObject pet = params.body().getJsonObject(); (2)
addPet(pet);
routingContext
.response()
.setStatusCode(200)
.end(); (3)
});
1 | 获取解析后的参数容器 |
2 | 提取解析后的请求体 |
3 | 写入 200 空响应 |
对于 showPetById
routerBuilder.operation("showPetById").handler(routingContext -> {
RequestParameters params = routingContext.get("parsedParameters"); (1)
Integer id = params.pathParameter("petId").getInteger(); (2)
Optional<JsonObject> pet = getAllPets()
.stream()
.filter(p -> p.getInteger("id").equals(id))
.findFirst(); (3)
if (pet.isPresent())
routingContext
.response()
.setStatusCode(200)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(pet.get().encode()); (4)
else
routingContext.fail(404, new Exception("Pet not found")); (5)
});
1 | 获取解析后的参数容器 |
2 | 提取解析后的路径参数 |
3 | 搜索宠物 |
4 | 如果宠物存在,将宠物写入响应中 |
5 | 如果宠物不存在,路由上下文以 404 失败 |
获取路由器
现在我们可以生成 Router
并添加“未找到”和“错误请求”错误处理器
Router router = routerBuilder.createRouter(); (1)
router.errorHandler(404, routingContext -> { (2)
JsonObject errorObject = new JsonObject() (3)
.put("code", 404)
.put("message",
(routingContext.failure() != null) ?
routingContext.failure().getMessage() :
"Not Found"
);
routingContext
.response()
.setStatusCode(404)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(errorObject.encode()); (4)
});
router.errorHandler(400, routingContext -> {
JsonObject errorObject = new JsonObject()
.put("code", 400)
.put("message",
(routingContext.failure() != null) ?
routingContext.failure().getMessage() :
"Validation Exception"
);
routingContext
.response()
.setStatusCode(400)
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(errorObject.encode());
});
server = vertx.createHttpServer(new HttpServerOptions().setPort(8080).setHost("localhost")); (5)
server.requestHandler(router).listen(); (6)
1 | 从 RouterBuilder 生成 Router |
2 | 挂载 404 未找到错误处理器 |
3 | 创建包含异常消息(如果有)的错误 JSON 对象 |
4 | 写入包含错误对象的响应 |
5 | 实例化 Vert.x HttpServer |
6 | 将路由器挂载到 HttpServer 实例上 |
完整代码
您可以在此操作指南的仓库中找到 APIVerticle
的完整源代码。
运行应用程序
APIVerticle
已经有一个 main
方法,因此可以直接用于
-
创建
Vertx
上下文,然后 -
部署
APIVerticle
。
您可以从以下方式运行应用程序
-
在您的 IDE 中,通过运行
APIVerticle
类中的main
方法,或者 -
使用 Maven:
mvn compile exec:java
您可以使用任何命令行工具(如 curl
)测试您的 API。
$ curl https://:8080/pets [{"id":1,"name":"Fufi","tag":"ABC"},{"id":2,"name":"Garfield","tag":"ABC"},{"id":3,"name":"Puffa","tag":"ABC"}] $ curl https://:8080/pets/3 {"id":3,"name":"Puffa","tag":"ABC"} $ curl https://:8080/pets/5 {"code":404,"message":"Pet not found"} $ curl -X POST -H "Content-type: application/json" --data '{"id":4,"name":"Alan"}' https://:8080/pets $ curl -X POST -H "Content-type: application/json" --data '{"id":4}' https://:8080/pets {"code":400,"message":"$.name: is missing but it is required"} $ curl https://:8080/pets [{"id":1,"name":"Fufi","tag":"ABC"},{"id":2,"name":"Garfield","tag":"ABC"},{"id":3,"name":"Puffa","tag":"ABC"},{"id":4,"name":"Alan"}]
总结
本操作指南向您解释了
-
如何从 OpenAPI 文档创建 Vert.x Web 路由器
-
如何提取解析后的请求参数
-
如何写入 JSON 响应
-
如何定义路由器范围的错误处理器
-
如何启动 HTTP 服务器并挂载生成的路由器