こんにちは、シタテルの茨木です。
シタテルではSCS(Sitateru-Control-System)という生産管理システムをRuby on Railsで実装し、AWSでホスティングしています。
SCS自体もViewを持っているのですが、徐々にAPI化とフロントエンドの分離を進めており、一部のフロントエンドは既にSPAで分離されていたりします。
今後はシステムをAPI仕様ベースで分離&疎結合化していきたいねーという流れで、API-Gateway系のプロダクト、今回は特にGoogle Cloud Endpointsに触ってみました。
やること
既にあるAWS上のOpenAPI仕様で実装されたAPIサーバと、Google Cloud Endpointsを接続して、APIアクセスを管理できるか見てみる。
とりあえずトラフィックが見えるところまでで、認証系とかはやりません。
構成イメージ
API-Server ---- ESP ---- Client App
|
|
Cloud Endpoints
ESP(Extensible Service Proxy)
ESPはEndpoints固有の要素で、リバースプロキシとしてAPIリクエストを一次受けし、Cloud Endpointsと連携しつつ、通していいリクエストだけバックエンド(API-Server)に流してくれます
- API-Serverの手前でESPを動作させるのが必須
- ESPはdockerで稼働が必要、ESPの稼働プラットフォームは任意
- ESPを間に噛ませさえすれば、API Serverのプラットフォームも任意
手順
身も蓋もないですが公式ガイドに書いてあるのを読むのが確実です
ざっと流れを書いておきます
GCPにプロジェクト作る
プロジェクトにサービスアカウント作って秘密鍵を払い出す
- サービスアカウントはESPがendpointにアクセスする際に使われます
OpenAPIの定義ファイル(いわゆるswagger)をAPIサーバから持ってくる
- 今回はgrape-swaggerで生成したものを使いました
- ガイドだとyamlになってますが、jsonでも読んでくれます
APIサーバのドメイン所有権の証明を行う
- 今回はGCP外のAPIサーバにつなぐので必要
- API定義を読ませたタイミングで、所有権を証明されていないドメインだと怒られます
- https://cloud.google.com/endpoints/docs/openapi/verify-domain-name
gcloud endpoints services deploy [API定義ファイル]
でendpoint構成をデプロイする- デプロイが通ると、下図の様にGCPのポータル上で見えるようになります
- あくまでendpoint構成をデプロイしただけで、ESPと繋いでないので何も起きません
- デプロイが通ると、下図の様にGCPのポータル上で見えるようになります
ESP用のインスタンスをAWS上に作って、dockerでESPを稼働させる
- docker導入は一般的な手順なので割愛
- ESP稼働させるdocker runは下記の様になります(サンプル)
sudo docker run \
--detach \
--name="esp" \
--net="host" \
--volume=$HOME/esp:/esp \
--publish=8082 \
gcr.io/endpoints-release/endpoints-runtime:1 \
--service=hogehoge.sitateru.com \
--rollout_strategy=managed \
--http_port=8082 \
--backend=https://hogehoge.sitateru.com \
--service_account_key=/esp/key.json
ざっとオプション説明
--service
endpoint構成のサービス名(≒APIサーバのドメイン名≒swaggerのhostエントリ)と一致させる
--backend
ESPのプロキシ先。APIサーバを指定する
--service_account
サービスアカウントの鍵ファイルを指定する
- ここまでやるとESP経由でリクエストが通るようになります
- curl等で試してみましょう
curl --request POST \
--header "Content-Type:application/json" \
--header "APIサーバ固有で必要なヘッダ等あれば" \
--data '{"email":"hogehoge", "password":"fugafuga"}' \
http://(ESPインスタンスのIP):8082/path/to/api
- ESP経由でのアクセスは、GCPポータルからログが確認できます
ハマった点
上記手順ではすんなりswaggerを読ませていますが、実際は結構エラーと戦いました。
ちゃんと読むとガイドにも書いてありますが、endpoint構成はOpenAPI仕様を完全にはサポートしていないようです。
例1. type: fileはダメっぽい
"/definitions/putApiV2Topics/properties/files/items/type": domain: validation; keyword: enum; message: value not found in enum; enum: ["array","boolean","integer","null","number","object","string"]; value: "file"
type: fileはサポートしてない。
仕様的にはstringに置換してよさそう?
例2. request-paramの渡し方に制限がある
ERROR: unknown location: http: body field path 'ids' must be a non-repeated message.
ERROR: unknown location: http: body field path 'api_v2_files' must be a non-repeated message.
ERROR: unknown location: http: body field path 'api_v2_items_id_files' must be a non-repeated message.
ERROR: unknown location: http: body field path 'emails' must be a non-repeated message.'
request-parameterのbody直下にarrayはサポートしない模様。
API側のパラメタ受け取り仕様で、arrayはobjectでくるむように作る必要がある?
まとめ
ESPまわりの構成は実際に組むまでイメージ湧かなかったので、その辺の助けになれば幸いです。
OpenAPIはほぼデファクトだと思っていたので、制約がいくつか出てきたのは意外でした。gRPC推しなんですかね?