使用 OpenAPI 与 TypeScript 进行契约测试
原文由 Alex O'Callaghan 于 发布,订阅该博客
在规模较大的组织中,多个软件开发团队协同工作时,系统间的跨边界交互往往是故障的高发点。明确定义 API 并就其行为达成一致,有助于大幅减少集成错误。借助 OpenAPI 和 TypeScript 这类工具,可以提供清晰的定义,并通过自动化测试进行验证。
场景
假设有一个工程师团队正在实现一个 Python 后端服务。他们正与另一个负责开发 Web 应用的团队紧密合作,该应用的部分功能将依赖这一服务。双方已就系统需求和 API 的运作方式达成一致,但随着时间推移,越来越多的团队开始成为该服务的调用方,功能不断新增和变更,缺陷也随之出现。
如何通过自动化测试来捕捉集成问题?端到端集成测试是个不错的想法,但也存在一些弊端。拉起整个技术栈需要各方在工具选型上达成一致,而且测试运行缓慢。如果再加上多个调用方,这类测试环境的搭建和维护将耗费大量的工程时间和精力。
契约测试,即验证对服务的请求是否返回了预期的状态码和数据结构,有助于发现那些未被察觉的缺陷和破坏性变更,且对技术选型的共识要求极低。
使用 OpenAPI 与 TypeScript
OpenAPI 是用于描述 API 的流行标准,兼容 JSON Schema,并得到了众多框架的支持。TypeScript 则是为 JavaScript 应用引入静态类型的热门选择。
如果后端服务提供了 OpenAPI 的 YAML 或 JSON 规范,前端应用就可以使用 openapi-typescript 为该服务的 API 生成类型定义:
$ npx openapi-typescript https://service.dev/openapi.json -o ./schema.d.ts这些类型可以在发起请求和处理响应时手动引用,也可以与 openapi-fetch 这类客户端配合使用,以提供类型安全的请求。
运行 tsc --noEmit 即可执行类型检查,捕捉潜在问题。
集成到 CI
在前端项目中,集成方式相对简单:只需在 CI 中增加一个步骤,从生产环境的服务拉取最新的 OpenAPI 规范,使用 openapi-typescript 生成类型定义,然后通过 tsc 运行类型检查。
对于后端项目,如果 CI 平台支持,还可以在调用方项目中触发流水线。例如,使用 GitLab CI 多项目流水线:
# Backend service
## Generate `openapi.json` and store as an artifact
generate-openapi:
stage: test
artifacts:
paths:
- openapi.json
when: always
script:
- make generate-openapi
## Trigger a downstream pipeline in consumer
validate-openapi:
stage: test
needs: ["generate-openapi"]
variables:
UPSTREAM_REF: $CI_MERGE_REQUEST_REF_PATH
trigger:
project: path/to/consumer
branch: master
strategy: depend
# Frontend service
## Generate types from `openapi.json` schema and use `tsc` to type check
validate-openapi:
stage: test
needs:
- project: path/to/service
job: generate-openapi
ref: $UPSTREAM_REF
artifacts: true
rules:
- if: $CI_PIPELINE_SOURCE == "pipeline"
script:
- npx openapi-typescript openapi.json --output path/to/schema.ts
- tsc --noEmit这样一来,后端服务的任何变更都会在各个调用方应用中得到验证,以检查是否存在破坏性变更。
总结
在理想情况下,跨职能团队会完整地维护自己的整个技术栈。但在规模较大的组织中,情况往往并非如此,跨团队协作的协调也颇具挑战。良好的沟通固然是关键,但自动化契约测试能够帮助捕捉那些原本会遗漏到生产环境的问题。即使是由单个团队维护的单一服务与调用方,随着系统复杂度的增长,API 变更也可能变得难以推断。OpenAPI 和 TypeScript 是提升开发者体验的优秀工具,可以非常简单地在系统之间建立起稳固、可测试的契约。
随机一篇博客
评论
登录后参与讨论