<-- mermaid -->

OpenAPI x TypeScriptでスキーマ駆動開発を実現する話

初めまして、AlphaDriveでWebアプリケーションエンジニアをしている水埜と申します。 本記事は、NewsPicks Advent Calendar 2022 の12/16 のブログとして記載させていただいています。

この記事でお伝えしたいこと

  • コードと分離したドキュメント(Excel)として管理していたバックエンドサーバーのAPI一覧をOpenAPIで管理
  • OpenAPIで定義した内容を自動でTypeScriptの型に変換
  • 生成した型をバックエンド(Express)とフロントエンド(React)で共有
  • API定義書の内容を自動でバリデーション&テスト

何が問題だったのか?

AlphaDriveでのプロダクト開発体制とエンジニアチームが組成される前段階から外部業者と共にプロダクトが開発開始された経緯もあり、現在の開発チームで内製開発体制に完全移行した段階で解消すべき技術的負債が顕在化している状態でした。 例えばバックエンドのAPI一覧がGit外のドキュメント上(Excel)で管理されており、以下のような問題点が存在しておりました。

ドキュメントの内容が正確でない

実装後に毎回ドキュメントをアップデートする必要があるのですが、どうしても更新が後手にまわりAPI定義書の内容がアプリケーションの実態と乖離していってしまう可能性がありました。また、ドキュメントの内容が間違えていたとしてもそれに気づくことができるような仕組みがないためドキュメントとしての信頼性が低い状態でした。

バージョン管理が行えない

Git外で管理していたため過去のAPI定義がどうなっていたのか知る術がなく、ドキュメントの管理が難しい状態でした。

仕様の変更の際に差分が分かりにくい

変更の差分がわかりづらく、Githubのプルリクのように変更をレビューする仕組みもありませんでした。

各API間で共通となるパラメーターの管理がしにくい

共通となるパラメーターを共通化する仕組みがないため、ドキュメント内で同じことを複数箇所で何度も書くことになります。変更が生じた場合複数箇所の記述を全てを書き直す必要があり、変更漏れが生じる可能性がありました。

フォーマットが自由記述になってしまい統一されない

定義書のフォーマットも決められておらず、更新した定義書をレビューする仕組みもなかったためフォーマットが統一されていませんでした。

コードやテストの自動化がしづらい

フォーマットが統一されていないため、定義書から型定義を自動生成したりバリデーションテストを自動実行する仕組みが導入しづらい状況でした。

どのように改善していったか?

今後開発を進めていくにあたって、OpenAPIを導入しスキーマ駆動で開発を進めていくように変更しました。

1. OpenAPIを導入

OpenAPIとは、RESTful APIを記述するためのフォーマットのことです。

以下公式からの引用です。

The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. An OpenAPI definition can then be used by documentation generation tools to display the API, code generation tools to generate servers and clients in various programming languages, testing tools, and many other use cases.

OpenAPI仕様(OAS)は、RESTful APIの標準的で言語に依存しないインターフェースを定義しており、人間とコンピューターの両方が、ソースコードやドキュメントにアクセスしたり、ネットワークトラフィックの検査を通じて、サービスの能力を発見し理解できるようにするものである。適切に定義されていれば、コンシューマーは最小限の実装ロジックでリモートサービスを理解し、対話することができる。 OpenAPIの定義は、APIを表示するためのドキュメント生成ツール、様々なプログラミング言語でサーバーやクライアントを生成するコード生成ツール、テストツール、その他多くのユースケースで利用することができる。

つまるところ、

  1. 言語に依存しない
  2. 人間とコンピューターの両方が理解できる
  3. 定義をもとにコードやテストを生成できる

などの特徴があります。

これを使うことで以下のようなメリットがあります。

  • Gitで定義書を管理できるため、バージョン管理、レビューが可能になる。
  • 一度フォーマットに慣れてしまえば記述は楽になるうえ、Swaggerを使用すればフォーマットを理解していない人でもAPIの仕様確認ができる
  • 仕様書を記述する人が変わってもフォーマットを統一して作成することができる
  • 共通となるパラメーターを共通化してまとめて書くことができる
  • パラメータのバリデーションが自動で行える(後述)
  • 仕様書からTypeScriptの型定義を自動生成することができるようになる(後述)
  • バックエンドのレスポンスが仕様書に沿っているかテストができるようになる(後述)

2. リクエスト、レスポンスのTypeScriptの型を自動生成

openapi2aspidaというnpm pakcageを利用することで、OpenAPIの定義書からTypeScriptの型定義を自動生成することができます。

また、バックエンド(Express)とフロントエンド(React)両方でTypeScriptで開発しているため、リクエスト、レスポンス、DTOの型を一箇所にまとめてしまいたいと考えています。現在はポリレポでの運用をしておりバックエンドのみで自動生成した型を利用しておりますが、いつかはモノレポにして型定義をバックエンド、フロントエンドで共通化してしく予定です。

3. パラメータのバリデーションを導入(予定)

API定義書を生成しても、定義通りにAPIを叩いてもらえるとは限らず、パラメータをバリデーションする必要があります。バリデーションを手作業で実装すると定義と乖離してしまう可能性があるため、OpenAPIの定義からバリデーションを生成したいと考えています。 まだ導入はしておらず構想の段階ですが、 express-openapi-validatorというライブラリを使用すれば自動バリデーションが実現できそうであり、検討していきたいです。

4. 実際のレスポンスが定義通りかチェックするテストを自動生成(予定)

ドキュメントと実装の乖離を防ぎ、よりスキーマを堅牢なものとするためにはレスポンスが定義通りのものかチェックするテストが必要です。こちらもまだ構想の段階ですが、openapi-response-validatorというライブラリが目的に合致している気がするため、導入を検討していきます。

まとめ

以上がAlphaDriveでスキーマ駆動開発を実現しようとしているお話でした。 まだOpenAPIを導入したばかりのため恩恵を受けている気はしませんが、一度環境を整備してしまえばだいぶ開発者体験が向上される気がしています。

最終的には以下の開発フローを目指しています。

  1. OpenAPIでのAPI定義を書き、プルリクエストをオープン
  2. API定義をレビューし、問題なければマージ
  3. API定義から型定義を生成し、バックエンド&フロントエンドの実装に着手
  4. レスポンスが定義通りであることを保証するユニットテストをopenapi-response-validatorで作成
  5. パラメーターをexpress-openapi-validatorでバリデーション
  6. バックエンドとフロントエンドのプルリクエストをオープン&レビュー

もし上記の開発フローが実現されれば、ドキュメント更新や型定義の時間を削減でき、生産性を大幅に向上できるのではないかと目論んでいます。

Page top