正文
当我们定义了这样一种语言去描述我们如何从 feed 里获取想要得到的数据时,剩下的问题就是:
-
写一个 parser,能够处理这个语言
-
使用我们定义的语言为每个 feed 撰写这样一个配置
最后,我们把问题精简成 1 个 parser + X 个配置文件,代码量也就是几百行。而配置文件,培训一下几乎是个程序员就能写出来。其结构如下:
日后的维护就是如何去扩充 parser 的一些辅助性函数,以及为新的 feed 撰写配置。
如果你看懂了这个例子,就会发现:
很多问题都可以化简为定义一个承上启下的中间语言(DSL),然后为其构建一个 parser。
而 OpenAPI,恰恰是这样一个在 API 客户端和 API 服务器之间的中间语言。我们利用好它的程序属性,可以做很多自动化(客户端代码生成,服务端代码生成,服务端测试生成,etc.)。
OpenAPI spec 简介
Open API spec 3.1.0 全文一万四千字,A4 纸打印的话要八十多页,是个庞大但并不复杂的 spec。要能够通过它来生成代码,第一步我们需要将其正确解析,处理好各种各样的情况,也就是说,我们要为其写一个 parser。而要撰写这样一个 parser,我们首先需要读懂 OpenAPI spec。好在 OpenAPI spec 并不复杂,很容易读。
首先,OpenAPI 所有数据结构的验证都使用 JSON schema(略有扩展),所以这部分我们只要大致了解一下,等具体使用的时候再详细看。JSON schema 有很久的历史了,所以相关的包也很多,各种语言的社区都找得到。在 Quenya 里,我就「暂时」使用了 ExJsonSchema 这个库。
然后,我们关注几大核心对象即可。
Server Object
Server object 在 swagger UI 里很有用,它定义了 API 可以通过什么 API 访问,以及 base path 是什么。比如:
http://localhost:4000/api/v1
,这里声明了 API 运行在
localhost
,使用
http
访问,端口是
4000
,base path 是
/api/v1
。这些信息都会被用在 Quenya 生成 API 代码时。比如:
servers:
- url: http://localhost:4000/api/v1
description: Local dev server
- url: https://api.todo.mvc/v1
description: Production server
OpenAPI Spec 不对 Server Object 做任何限制,但在 Quenya 里,至少要声明一个
localhost
,Quenya 会用这里的信息来正确生成本地运行的服务器监听的端口以及正确的路由,比如:
get("/swagger/main.json", to: SwaggerPlug, init_opts: [app: :todo])
get("/swagger", to: SwaggerPlug, init_opts: [spec: "/swagger/main.json"])
forward "/api/v1", to: Todo.Gen.ApiRouter, init_opts: []
match(_, to: Quenya.Plug.MathAllPlug, init_opts: [])
这个很重要,我们要确保生成的 API 服务可以无需任何修改就能在 swagger 里运行。
Path / Operation object
在任何 API 项目中,最核心的部分就是每条路由及其处理函数的定义。在 OpenAPI spec 中,这是由 Path 以及 Path 内部的 operation 对象定义的。比如如下的 path
todo/{todoId}
包含一个
patch
operation,它的定义如下: