8章 外部APIパターン
- 外部APIを公開する際の問題点
- APIゲートウェイパターン
- BFFパターン
- GraphQL
などが紹介されています。
外部APIを公開する際の問題点
仮に個々のサービスのAPIを外部APIとして公開してしまった場合の問題点
- マイクロサービスアーキテクチャだとサービスの粒度が細かいので、結果的にAPIの粒度も外部APIとしては細かくなりすぎる。
- Order情報を取得するのにも、数回のAPIを呼ばないといけない
- サービスの粒度や、内部APIを変えられなくなる
- 内部APIはそもそもhttpを喋れないかもしれない
- クライアントの種類によっては、APIの要件が変わってくる
- それを各マイクロサービスが吸収するのか?
というわけで、内部APIをそのまま公開しても良いことはあまりないので、フロントにAPIゲートウェイを立てます
APIゲートウェイパターン
マイクロサービスベースのアプリケーションへのエントリポイントとなるサービス
以下のようなことを行う
- リクエストのルーティング
- httpを転送すればいいだけの場合
- API合成
- 粒度の細かいバックエンドAPIの結果を集約して、クライアントに使いやすい形にして返す
- プロトコル変換
- バックエンドがメッセージングなどhttp以外のAPIを持つ場合は、外部に対してhttpベースのAPIを公開する
- エッジ機能
- 認証、認可、流量制御、キャッシング、メトリクス収集、リクエストロギング
- 11章では上記のうち、認可に関してはパスベースの簡単なものならいいが、それ以上のものはサービスの詳細に深く関わるので、各サービスで実装して方がいいとしている
一応、欠点としては、メンテナンスが必要なサーバーが増えるというのがあるけど、欠点を補ってあまりあると言って良いでしょう
BFFパターン
- BFF(Backend for Frontend)パターン
- 一口に外部APIといっても、クライアントの種類(Webであったり、モバイルであったり)によって、API要件が違う場合がある
- 要件が大きく違うのであれば、いっそクライアントの種類ごとにAPIゲートウェイを別立てにして、クライアント開発チームが、自身向けのAPIゲートウェイの開発と運用をするというのがBFFパターン
- アプリロジックの役割分担という観点から言えば合理的
- 一方で、要求されるテクノロジーやスキルが大きく違うので実際はそれほどうまくはいかないと思う
- 特に運用の部分は11章で説明されている横断的関心事を一通りこなさないと行けないので、クライアントチームがサーバーの運用に深く関わるのはあまりよろしくないと思う
APIゲートウェイの要件
- リクエストルーティング
- API合成
- エッジ機能
- プロトコル変換
ルーティングに関しては、パスベースだけでなく、メソッドベースもできないと7章のCQRSパターンを実現できない(GETとそれ以外で、転送先を変える必要がある)
既製のAPIゲートウェイ
- 以下が挙げられている
- AWS API Gateway
- AWS ロードバランサ
- kong
- Traefik
- どれも先に上げた要件をすべて満たすわけではない
- 特にAPI合成は、個別に実装が必要なので、できあいのもので実現するのは難しい
APIゲートウェイを作る
- 作者のおすすめフレームワークはSpring Cloud Gateway
- メソッドベースのルーティングも含めて、先に上げた要件は一通り満たせるらしい
- ただしhttpリクエストを、kafkaベースのメッセージングにプロトコル変換しながらルーティングできるのかは本文からは分からなかった
- 実装も典型的なSpring風のものなので、経験者にはとっつきやすそう
GraphQL を使った API ゲートウェイの実装
- API GatewayをGraph QLで実現する話
- クライアント側でqueryの内容を変えられるので、graph qlのエンドポイントを一つ作るだけで様々な用途に対応できる
- rest apiだと、多少はパラメータ化できるものの、普通はいくつものapiをつくることになる
- GraphQL スキーマ
type Query {
orders(consumerId : Int): [Order]
order(orderId : Int): Order
consumer(consumerId : Int): Consumer
}
type Order {
orderId: ID,
consumerId : Int,
consumer: Consumer
restaurant: Restaurant
deliveryInfo : DeliveryInfo
...
}
- エンドポイントのところでtype Queryで定義されたクエリーを投げられる
- エンドポイントがリクエストを受けたあとは、バックエンドのマイクロサービス群に、必要なクエリーを発行して、情報をあつめてレスポンスを返す
- この例では、Order、Consumer、Restaurant、DeliveryInfoはそれぞれ別のマイクロサービスが担当している
- node.jsのApollo GraphQLというExpress上で動かせるフレームワークでの実装例が書いてある