Google Cloud Endpointsを利用してAPIを作ってみよう

この記事は、[All About Group（株式会社オールアバウト）Advent Calendar 2018](https://qiita.com/advent-calendar/2018/allabout) 13日目の記事です。

# 概要
新たにAPIを作成する必要があり Google Cloud Endpoints を使いました。
https://www.slideshare.net/GoogleCloudPlatformJP/google-cloud-platform-89167308
モニタリングやログ確認、さらには仕様書的なものまで揃うので、とても便利です。

ちなみにチルテレというサービスのAPIで利用しております。（アプリもあります！）
【宣伝】https://chill-tv.com/

# できること
- Googleの各種APIと同じように扱うことができます
	- Cloud Endpointsをデプロイすると、「API とサービス」一覧に表示されます
![APIとサービス画面.png](https://qiita-image-store.s3.amazonaws.com/0/98891/f4c48d8c-d477-400b-2cf2-e1fcddf58911.png)
- Googleで発行したApiKey認証をバックエンド（アプリ側）に実装せずに可能になります
	- アクセス制限が必要なAPIの場合「API とサービス」からAPIキーを発行してopenapi.yamlで定義すれば、アクセス制限が可能です
- モニタリングやログの確認が画面上からできます
	- リクエスト数、レイテンシ、5xxエラー率など確認が可能です
![エンドポイント管理画面.png](https://qiita-image-store.s3.amazonaws.com/0/98891/7eff9ba7-a1f2-4c20-88bb-83e96892e12f.png)

# 概要とアーキテクチャ
https://cloud.google.com/endpoints/docs/openapi/about-cloud-endpoints?hl=JA
https://cloud.google.com/endpoints/docs/openapi/architecture-overview?hl=JA

- Extensible Service Proxyを利用 - Google Cloud Endpoints の機能を挿入します（Google Service Controlに問い合わせたりする、　Endpointsの中核）
- Google Service Control - API 管理ルールを適用
- Google Service Management - API 管理ルールを設定
- Google Cloud SDK - デプロイと管理に使用
- Google Cloud Console - ロギング、モニタリング、共有に使用

何が何だか今はわからなくても、この先を進めると理解できてくると思います:grin:

# やること
それでは、実際にやることを上げていきます。

## openapi.yamlを作成する
APIのURLエンドポイントを定義するファイルです

- Swaggerとほぼ同義になります  
https://cloud.google.com/endpoints/docs/openapi/openapi-overview?hl=JA
- エディターを使うと便利です  
https://editor.swagger.io/#/

## Cloud Endpointsへdeploy
問題なければ、openapi.yamlを利用してdeployをします。

```shell
$ gcloud endpoints services deploy openapi.yaml
#※ERROR: (gcloud) Invalid choice: 'endpoints'.的なエラーが出た場合gcloudのバージョンが低いので、gcloud service-management deploy に変更
```
- デプロイできたかは下記で確認ができます

```shell
$ gcloud endpoints services describe {openapi.yamlに記述したhost名}
#※ERROR: (gcloud) Invalid choice: 'endpoints'.的なエラーが出た場合gcloudのバージョンが低いので、gcloud service-management describe に変更
```

### openapi.yaml作成時に気をつけること
- バージョン 2.0 が使えます（3.0があるがEndpointsでは使えません（2018/12/13現在））
- ApiKeyによる認証の項目は `securityDefinitions` で定義できます
- `in`の項目で`query`や`header`など指定が可能です  

```yaml
securityDefinitions:
  api_key:
    type: "apiKey"
    name: "key"
    in: "query"
```
- 各URLのエンドポイントで `security` の項目を追加することでURLごとにアクセス制御が可能です  

```yaml
paths:
  /articles:
    get:
      tags:
      - "article"
      summary: "Get article list"
      description: "We will get a list from the latest articles"
      operationId: "articles"
      produces:
      - "application/json"
      parameters:
      - name: "limit"
        in: "query"
        description: "Number of items to be acquired"
        required: false
        type: "integer"
      - name: "page"
        in: "query"
        description: "Number of pages to acquire"
        required: false
        type: "integer"
      security:
      - api_key: []
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/Articles"
        400:
          description: "The specification is incorrect"
        404:
          description: "Could not be located"
```

## バックエンドを作成
- 今回はGKE上で作成しました
	- その他AppEngineやGCEでも可能です  
	https://cloud.google.com/endpoints/docs/openapi/tutorials?hl=JA

### deploymentの設定を調整する  
https://cloud.google.com/endpoints/docs/openapi/specify-proxy-startup-options?hl=ja

- Extensible Service Proxyをバックエンド（アプリケーション）の前に追加します  
	- このproxyがopenapi.yamlで設定した認証などのアクセス制御、モニタリング、ロギングなどをやってくれます
	- 下記のように設定しました

```yaml
      containers:
        # [START esp]
        - name: esp
          image: gcr.io/endpoints-release/endpoints-runtime:1
          args: [
            "--http_port", "8081",
            "--backend", "{バックエンドのアプリケーション先を指定}",
            "--service", "{Endpoints サービスの名前}",
            "--rollout_strategy", "managed",
          ]
        # [END esp]
          ports:
            - containerPort: 8081
        - name: xxxx-api-container
          ports:
            - containerPort: 80
        以下にアプリケーションコンテナの設定....
```
※GKEのdeploymentについては下記を参照ください
https://allabout-tech.hatenablog.com/entry/2017/12/08/080800

## ApiKeyを発行
- GCPの`APIとサービス`の`認証情報`から`認証情報を作成` で今回利用するためのAPIキーを発行します
	- `APIの制限`にopenapi.yamlで追加したAPIが選択できるので、必要であれば追加しても良さそうです
![認証情報画面.png](https://qiita-image-store.s3.amazonaws.com/0/98891/a4cb04f0-19bc-e7a9-23dc-9b5dabc76052.png)

# 確認
- URLにアクセスしてみましょう（ApiKeyを`?key=xxxx`でURLに追加します）
- ApiKeyがない場合はアクセスできないか確認しましょう

# リリース方法
APIのURLエンドポイントが変わったり追加があった場合は、Cloud Endpointのdeployとアプリケーションのdeployを行う必要があります

```shel
$ gcloud endpoints services deploy openapi.yaml
```

# デベロッパーポータル  
- openapi.yamlをもとに作成されたAPIドキュメント自動作成機能になります  
	- https://cloudplatform-jp.googleblog.com/2018/05/now-you-can-automatically-document-your-API-with-Cloud-Endpoints.html
- 動作をテストしたり、APIドキュメントとしても機能します
![デベロッパーポータル画面.png](https://qiita-image-store.s3.amazonaws.com/0/98891/774021cf-6d8c-d030-badc-f4bb98cbe0ac.png)

# 主な注意点
下記を上げておりますが、私が躓いた箇所になります

- Extensible Service Proxy ではGoogle Service Controlへの問い合わせをキャッシュするが、バックエンド（アプリ側）のキャッシュは別になります（CloudCDNなど利用する）
- Google Service Control, Google Service ManagementをGKEなどで利用する場合は、クラスタに以下の権限を付与する必要があります
	- サービス コントロール = 有効
	- サービス管理	= 読み取りのみ
	- ※GKEとは → https://qiita.com/numa_numa/items/f3117e1d99360ac110ec#gke-google-kubernetes-engine-%E3%81%A8%E3%81%AF

# まとめ
実際に動かすまでに躓いたところもありましたが、それほど難しくなく導入ができました。
今後も便利なサービスをうまく利用して、開発していきたいと思います。