我谈 OpenAPI
OpenAPI 很有吸引力,但是或许还能更进一步?
OpenAPI?
OpenAPI 是一种用于描述后端 API 的规范,虽然你可能并没有听过它,但是可能已经在项目中使用了:
这个总认识吧?这是 OpenAPI 的前端(Swagger UI)。后端生成 OpenAPI Spec,再丢给 Swagger UI,就能得到上面那样的文档。*
如果对 OpenAPI 有兴趣,Swagger Editor 或许会对你的理解有帮助。
痛点
如果没有一个描述 API 的规范,很容易发生这些问题:
- 无标准化描述方式增加沟通成本
- 难以清晰描述 API 的变更
- 手动维护的文档很容易滞后
- 测试困难、难以协调
因此 OpenAPI 的出现是必然的,但是到此为止了吗?
即便有了 OpenAPI,编写请求代码仍是繁复却又必须的工作,既然有了统一描述 API 的规范,请求代码的批量生产就有了眉目。
客户端生成?
使用 OpenAPI Spec 生成代码可能是个好选择,OpenAPI 包含的信息足以实现一个标准的、类型安全的请求客户端。
JS 生态也有很多选择了:
- swagger-api/swagger-codegen: swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.
- OpenAPI Generator
- ferdikoomen/openapi-typescript-codegen: NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification
但是问题似乎没有得到解决。
代码生成虽然能解决批量生产的问题,但是代码生成本来就是很难做干净的,会带来其他问题:
- 代码冗余
- 生成代码可读性差,难以调试
- 难以甚至无法定制
也许没有必要做那么多,简单一点就好?
类型生成!
也许你并不需要一个功能完备的请求客户端,只需要在写 fetch
的时候得到类型提示。如此设计,就解决了上面提到的大部分问题,至于对请求的封装?放在其他地方就好了。
社区中相关生态只找到一个 OpenAPI TypeScript,如其名,它只做 OpenAPI Spec 到 TypeScript 类型定义的转换,而不参与其他事务。
OpenAPI Typescript 同样提供了 OpenAPI fetch,这个包浅层封装了 fetch
,并通过类型体操的方式,将转换后的类型定义附加在请求的每一个参数上,以此获得了类似请求客户端的类型安全。
再来谈类型生成最大的优势:非常好封装。
首先 openapi-fetch 只是包了一层 fetch
,不会有抽象过度。它还提供了一套中间件,这足够完成大部分合理的封装。其次,openapi-fetch 支持传入 fetch
实现,意味着也可以通过 extends ky 来注入逻辑,这就足以覆盖所有场景。
当然,在请求代码中挂太多自定义逻辑早就不是不被认为是一个好的模式了,在现代前端开发中,这类逻辑一般会放在 react-query
这样的高层次的异步状态管理库中。
痛点好像都解决了,吗?
未来
OpenAPI 的表现力是远远不够的,无法适应这个时代。
比如,目前 OpenAPI 只能描述简单的 Request-Response 模式,但是自 2023 年 AI 大热之后,流式 API 也跟着炙手可热起来,而 OpenAPI 无法描述流式 API 成了一个很大的问题。
流式 API 不能简单的用 Request 和 Response 描述,因为流式显性地引入了状态机,需要对其状态转换过程进行建模,使开发者能够理解数据流的顺序和条件,这就对描述它的语言(DSL)提出了很高的要求,而且,这个语言及其标准是长期空缺的。
那么未来如何呢?我不知道。