freeeの開発情報ポータルサイト

Public APIのバージョニングの仕組みを解説

こんにちは、freeeでアプリケーションエンジニアをしているmonacaです。

私が前回書いた記事では、主にfreeeでの働き方について書きました。 現在私は、愛知県に住みながら、Public APIやアプリストアを開発する東京のLEGOチームで仕事をしています。

いまは、コロナウィルスの状況を見て、中部オフィスに出社し、社内でワイワイしながらリモートで仕事をしたり、ちょっと変わった体験を楽しんでいます。

中部オフィスの情報は、moaiさんが書かれた記事があるので、興味があったら見て下さいね。 developers.freee.co.jp

さて、今回は、freeeのPublic APIのバージョニングの仕組みについて、書いてみようと思います。

APIのバージョニングについて

アイキャッチ画像

世の中の多くのPublic APIがそうであるように、freeeのPublic APIも、見えるところ、見えないところを含め日々改善を繰り返しています。 その繰り返しの中で、背後にあるビジネスロジックに大きな変更が入ったり、技術的な負債を解消するタイミングで、インターフェイスの後方互換を取れなくなる場合があります。

そういったときに、APIの新バージョンが発生します。

freeeのPublic APIでは、APIの旧バージョンから新バージョンへ一気に移行するのではなく、ある程度の移行期間をおいて新バージョンに切り替えています。 移行期間では、同じAPIエンドポイントをcallしても、アプリからの指示によって、新旧どちらのバージョンで処理するかを切り替えられるようになっています。 ここでは、その並行バージョン処理である、APIのバージョニングの仕組みについて書こうと思います。

また、今回説明するバージョニングの背景やその考え方について、LEGOチームのまっつーさんが書いた記事"会計フリー Public API史上初の新バージョン移行を完遂しました"があるので、よければ読んでみて下さい。バージョニング機構の様々な選択肢と、それらを選んだ理由について書かれています。

目次

  • アプリが利用したいAPIバージョンを指定する
  • 有効なバージョンを管理する
  • 指定されたAPIバージョン情報をリクエスト単位に保持する

アプリが利用したいAPIバージョンを指定する

先に挙げたまっつーさんの記事に、バージョン指定方法を検討したときの詳細が書かれていますが、freeeのPublic APIでは下記3つのAPIバージョン指定方法の案から、3のヘッダーでAPIバージョンを指定する方法をとりました。

  1. pathで表現
  2. アプリ管理画面から指定
  3. ヘッダーで指定(この案を採用)

これは、APIのクライアントであるアプリが、リクエストヘッダーにバージョン情報を追加することで実現します。 例えば、人事労務APIの場合、下記のようなリクエストヘッダーを追加します。

FREEE-VERSION: <バージョン日付>

現在、新旧バージョンの並行運用が行われている、人事労務APIで最新バージョンを指定するには、 リクエストヘッダーにFREEE-VERSION: 2022-02-01 を追加します。

APIではリクエストを受け付けたときの初期化処理で、このヘッダー情報をバージョン情報に変換して、グローバルに保持します。その後、API処理の随所でこのバージョン情報を参照し、新旧バージョン処理ロジックへの振り分けを行っています。

バージョンアップのサイクル

freeeのPublic APIでは、不具合はもちろん、大小含めた品質改善を日々行い、日次ベースで最新版を本番環境に反映しています。 これらの変更では、API仕様に影響のないものが殆どですが、中には前述したようなビジネスロジック変更や技術的負債の解消のために、API仕様の変更を避けられない破壊的変更が発生します。

下図のように、APIの変更が繰り返され、それより大きなサイクルで破壊的変更=APIの新バージョンが発生します。

通常の変更が繰り返され、最終的に破壊的変更が発生して新バージョンが発生する図

freeeのPublic APIでは、この破壊的変更のサイクルに対応できるように、APIバージョンの有効期限を管理しています。

有効なバージョンを管理する

API内部では、リクエストヘッダー情報とリクエストされた時点での利用可能なバージョンとを照合して、今回のリクエストを、どのAPIバージョンとして処理するかを決めます。

これらの処理うち、指定されたバージョンの有効性確認や、バージョン情報をグローバルに参照可能にする仕組みが、Ruby on Railsの処理レイヤーの上位にあるMiddlewareとして実装されています。 また、このMiddlewareは、今後追加されるかもしれないAPIのためにRubyのgemとして実装し、同じ実装作業を繰り返さないようにしてあります。 gemは、Rubyの外部ライブラリです。

また、指定されたバージョンの有効性確認に使う設定は、下記のような構成情報に切り出してあります。

versions:
- name: '1980-01-01'
  begin_time: '1980/01/01 11:00:00 +0900'
  end_time: '2030/12/31 00:00:00 +0900'
- name: '2022-02-01'
  begin_time: '2022/02/01 11:00:00 +0900'
  end_time: '2030/12/31 00:00:00 +0900'

バージョン毎に、有効期間の設定があるのが分かりますね。

指定されたAPIバージョン情報をリクエスト単位に保持する

Middleware層で判定されたAPIバージョンは、RequestStoreというgemの機能によって保持され、処理の各所からアクセスできるようになっています。

RequestStoreを利用する理由は、バージョン情報を下図のように、(1)リクエスト処理内でグローバルに参照できて、(2)別のリクエストには参照させないようにするためです。RequestStoreの使い方は、Webでも多くの解説記事を参照できると思いますので、興味がある方はぜひ検索してみて下さい。

下図は、処理スレッドで実行されるリクエスト処理が、個別にバージョン情報を維持管理できることを表しています。

Request Storeを使って同じ処理スレッド内でもバージョン情報にリクエスト単位のライフタイムを持たせる

リクエスト処理の最後に、RequestStoreが、バージョン情報を自動的にクリアしているのが分かります。

おわりに

freeeのPublic APIのバージョニングの仕組み、どうだったでしょうか?

今後も機会があれば、freeeのPublic APIの仕組みについて解説しようと思いますので、そのときは是非また読んでみて下さい!

freeeの中部オフィスでは、中部から日本中で使われるプロダクトを世に届けたい方を募集しています。

jobs.freee.co.jp