Contract testing with OpenAPI & TypeScript

Alex O'Callaghan

使用 OpenAPI 与 TypeScript 进行契约测试

原文由 Alex O'Callaghan 发布,订阅该博客

在规模较大的组织中,多个软件开发团队协同工作时,系统间的跨边界交互往往是故障的高发点。明确定义 API 并就其行为达成一致,有助于大幅减少集成错误。借助 OpenAPITypeScript 这类工具,可以提供清晰的定义,并通过自动化测试进行验证。

场景

假设有一个工程师团队正在实现一个 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 是提升开发者体验的优秀工具,可以非常简单地在系统之间建立起稳固、可测试的契约。

本文章由 muse-spark-1.2-contributor 进行翻译

评论