【GCP + kintone】kintone外部からkintone のデータを読み込む

# 大まかな手順として
大前提として、kintone と Google Cloud Platform（以下、GCP）のアカウントは取得しているものとします。

## kintone 側
1. アプリを用意する
2. 上記アプリの API TOKEN を発行する
3. 上記アプリが所属するドメインとアプリIDをメモっておく

## Google Cloud Functions 側
1. GCP内でプロジェクトを用意する
2. GCPのプロジェクト内で、Google Cloud Functions を有効化
4. GCP側に require と @kintone/rest-api-client をインストール
5. ローカル環境に gcloud cli をインストール
6. GCP のデフォルトリージョンを変更
7. gcloud init でローカル環境の初期化
8. ローカル環境に Google Cloud Functions 用のプロジェクトフォルダを作成
9. ローカル環境にも require と @kintone/rest-api-client をインストール
10. 上記フォルダ内に、index.js作成
11. gcloud functions deploy
12. Google Cloud Functions でテスト

# kintone 側の作業
## アプリを用意する
kintone のアカウントについては、[kintone環境の取得方法 (開発者ライセンス)](https://qiita.com/RyBB/items/73c50f1751ad137ba410)を、

kintone のアプリについては、[kintoneの使い方 (データベース編)](https://qiita.com/RyBB/items/daabb9b60d804ee2242f)をご参照ください。

[@RyBB](https://qiita.com/RyBB)さんの記事にはものすごく助けられました。
ありがとうございます！

では、kintone のアプリを用意しましょう。

kintone にログインしてアプリを制作しましょう。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/096b850a-60b7-a454-5085-db8215bdaa7c.png)
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/4b640878-4092-1d97-8a8d-de0c3c9a5f6b.png)
フィールドを並べて、アプリを作っていきます。

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/b7c90a61-2ebb-959d-153f-219f8dfec939.png)
右上にある【新しいアプリ】と言う欄にアプリ名をつけられますが、ここで入力したものは人類側のためのもので、日本語よろしくないんじゃないだろうか？と言った気遣いは無用のようです。

とは言え、人類に対する気配りもそれなりにはしておきましょう。

で、ここで知見なのですが、[kintoneの使い方 (データベース編)](https://qiita.com/RyBB/items/daabb9b60d804ee2242f)にもある通り

* kintone のアプリ ≒ データベース
* kintone のアプリで言うところのフィールド ≒ カラム

と考えても大きく差し支えはないので、ガシガシやっていきたいところなのですが、フィールド設置の際にちょっと注意を
![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/c3e160eb-e5b6-fccb-5c09-be115cf8447d.png)
フィールドはそれぞれに細かく設定ができるのですが、kintone REST API などを使用してこのアプリのレコードをJSONで吐き出させた場合、key は人類用のフィールド名ではなく、プログラム用のフィールドコードのほうが使用されます。

フィールドを設置したそのままだと、フィールドコードはフィールドタイプがそのまま残ってしまいます。

なので、フィールドコードもきちんと変えておく。

この際、フィールドコードをアルファベット、数字、アンダースコア（もちろん全部半角）で設定しておくと、後々VSCodeで入力補完が効くようになります。

なので、極力半角英数で設定しておくと幸せになれます。
![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/eae50e3f-57dd-82c7-064a-8a24d32a5fde.png)
今日の10円より明後日以降の500円を。

## アプリの API TOKEN を発行する
作業は下図の通り
![006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/94a6e27b-b33a-6f96-3b31-36ee0f9cf510.png)
![007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/6741e3e7-955a-d76b-60a1-57ceb3a68c03.png)
![008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/fabde731-790a-a2c6-d55b-0e97e60bcf97.png)
そうすることでAPI TOKENが発行されます。
![009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/0d260ee2-cb25-3f7e-17d3-cf81f9b23d6b.png)

API TOKENは一つのアプリに対して複数発行ができます。
また、TOKENごとにアクセス権が設定でき

* レコード閲覧 : GET
* レコード追加 : POST
* レコード編集 : PUT
* レコード削除 : DELETE

に対応しています。

一つのTOKENに複数権限を与えてもよし、それぞれ別に発行してもよし…

## 上記アプリが所属するドメインとアプリIDをメモっておく
kintone内部（いわゆるkintone JavaScript カスタマイズ）でも、外部からであっても、kintone REST APIを叩く場合に必須になるのが、対象となるアプリが所属しているサブドメインとアプリIDです。

確認方法は色々あるのですが、一番確実なのは下図。
![010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/ae5bfe8c-5488-47d7-1dcb-9fa065a8bf45.png)
図の通りkintoneで作成したアプリを起動すると、URLは下記のようになっています。

https://サブドメイン.cybozu.com/k/アプリID/

それぞれ該当する項目をメモっておいてください。

あと、この後GCPからこのアプリのレコードを引っ張ってくるので、レコードの追加も忘れずに。
![011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/85ef2ab2-cf2a-9e34-a2ea-0909bee85bce.png)

# Google Cloud Functions 側の作業
## GCP内でプロジェクトを用意する
さて、GCPでの作業です。
まずはプロジェクトを作ります。

GCPのダッシュボードに入り、自分の所属組織に移動した後、プロジェクトを作ります。

![012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/96a812bb-f5db-b066-816c-6d41a713b82b.png)
ふむ〜

![013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/f0d7f52e-8c98-3d26-4c61-1e033fd8491c.png)
プロジェクトの作成には1分弱お時間がかかります。

## GCPのプロジェクト内で、Google Cloud Functions を有効化
プロジェクトができたら、Google Cloud Functions（以下、Functions） を有効化します。
![014.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/45d21589-491c-b6ef-1126-d8e88cc6dfaa.png)
これまたお時間ちょっとかかる
![015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/15cba4a9-773b-34a3-7245-4461027218e7.png)
一応この画面になるまで待ちましょう
![016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/b854c4b8-5eff-ee53-eaec-8b98aef25c61.png)

## GCP側に require と @kintone/rest-api-client をインストール
おそらく高確率で【require】はいらないと思うのですが、AWS Lambdaで怒られた経験があるので、一応入れておきます。

どう入れるかというと。
![017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/8e86f5e4-d8c8-2e99-d525-9020214e443a.png)
Cloudシェルを立ち上げて

![018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/3287ab63-b8fd-21e7-d826-ffdd0d979b92.png)
上図のように出現したターミナルに下記コマンドを打ちます。

```
npm install require
```

と

```
npm install @kintone/rest-api-client
```

これでGCPに require と @kintone/rest-api-client がインストールできました。

GCPの方は一旦ここまで。

## ローカル環境に gcloud cli をインストール
GCPもちゃんと（というか当然）cli が用意されています。
未導入の方は下記からどうぞ。

* [mac OS](https://cloud.google.com/sdk/docs/quickstart-macos?hl=ja)
* [windows](https://cloud.google.com/sdk/docs/quickstart-windows?hl=ja) 

## GCP のデフォルトリージョンを変更
GCPは何もしないとリージョンが us-central になってしまうので、このタイミングで変えておきましょう。

お手元のパソコンのターミナルを起動して

```
gcloud config set compute/region {REGION}
```

{REGION}には、お好きなリージョンを入力してください。

* 東京 : asia-northeast1
* 大阪 : asia-northeast2

## gcloud init でローカル環境の初期化
gcloud cli にて、ローカル環境を初期化します。

お手元のパソコンのターミナルを起動して

```
gcloud init
```
と打つと、会話形式で色々聞かれます

```
Welcome! This command will take you through the configuration of gcloud.

Settings from your current configuration [default] are:
accessibility:
  screen_reader: 'True'
compute:
  region: asia-northeast1
  zone: asia-northeast1-b
core:
  account: あなたのGCPログインメアド
  disable_usage_reporting: 'True'
  project: プロジェクト名
functions:
  region: asia-northeast2

Pick configuration to use:
 [1] Re-initialize this configuration [default] with new settings 
 [2] Create a new configuration
Please enter your numeric choice:  ← 1でOK

```
```
Your current configuration has been set to: [default]

You can skip diagnostics next time by using the following flag:
  gcloud init --skip-diagnostics

Network diagnostic detects and fixes local network connection issues.
Checking network connection...done.                                                                                                                 
Reachability Check passed.
Network diagnostic passed (1/1 checks passed).

Choose the account you would like to use to perform operations for 
this configuration:
 [1] あなたのGCPログイン用メアド
 [2] Log in with a new account
Please enter your numeric choice:  ← 1でOK
```
```
You are logged in as: [あなたのGCPログイン用メアド].

Pick cloud project to use: 
 〜 中略　〜
 [4] yobuze-kintone
 [5] Create a new project
Please enter numeric choice or text value (must exactly match list 
item):  ← 今回作ったプロジェクト名を選択

```
```
Your current project has been set to: [yobuze-kintone].

Not setting default zone/region (this feature makes it easier to use
[gcloud compute] by setting an appropriate default value for the
--zone and --region flag).
See https://cloud.google.com/compute/docs/gcloud-compute section on how to set
default compute region and zone manually. If you would like [gcloud init] to be
able to do this for you the next time you run it, make sure the
Compute Engine API is enabled for your project on the
https://console.developers.google.com/apis page.

Your Google Cloud SDK is configured and ready to use!

* Commands that require authentication will use あなたのGCPログインメアド by default
* Commands will reference project `yobuze-kintone` by default
Run `gcloud help config` to learn how to change individual settings

This gcloud configuration is called [default]. You can create additional configurations if you work with multiple accounts and/or projects.
Run `gcloud topic configurations` to learn more.

Some things to try next:

* Run `gcloud --help` to see the Cloud Platform services you can interact with. And run `gcloud help COMMAND` to get help on any gcloud command.
* Run `gcloud topic --help` to learn about advanced features of the SDK like arg files and output formatting
```
ここまで出たらOKです。

## ローカル環境に Google Cloud Functions 用のプロジェクトフォルダを作成

では、お手元のパソコンで Functions 用のフォルダを作り、作業準備をしましょう。

お好きな名前でフォルダを作ったら、ターミナルでそのフォルダまで移動して、下記コマンドを。

```
npm init
```

色々と質問が来ますが、全部 enter でOK。

```

〜 前略 〜

package name: (yobuze-kintone) yobuze-kintone
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC)

〜 中略 〜

Is this OK? (yes) yes

```

## ローカル環境にも require と @kintone/rest-api-client をインストール
続いて、ローカル環境にも require と @kintone/rest-api-client をインストール。
だから require はいらないきが…

あ、package.jsonにも反映したいので、GCPのときとちょっとコマンドを変えましょう。

```
npm install --save require
```

と

```
npm install --save @kintone/rest-api-client
```
です。

このタイミングで node_modules フォルダに色々入ります。

```
.
├── node_modules
│   ├── @kintone
　〜 中略　〜
├── package-lock.json
└── package.json
```
## 上記フォルダ内に、index.js作成
ここからはVSCodeなんかのエディタで index.js を書きます。

``` javascript
const { KintoneRestAPIClient } = require('@kintone/rest-api-client');

/**
 * exports の後の getRecordsKintone の部分がエントリポイントになります
 * 実際に呼び出す場合には下記のような URL を叩きます
 * https://asia-northeast2-GCPのプロジェクト名.cloudfunctions.net/getRecordsKintone
 * 
 * req は、この Functions を呼び出す際に色々引き渡すために使用
 * 
 * res は、この Functions を実行した結果が出力されます 
 */

exports.getRecordsKintone = (req, res) => {

  // kintone の呼び出し設定です
  const client = new KintoneRestAPIClient({
    // サブドメインは、kintoneの作業中にメモりましたよね？
    baseUrl: 'https://サブドメイン.cybozu.com',
    auth: {
      // APIトークンもメモりましたよね
      apiToken: 'APIトークン'
    }
  });
  
  // アプリIDもメモ（略）
  const APP_ID = アプリID;
  const params = {
    app: APP_ID
  };
  
  // ここで kintone を呼び出しつつ、アプリ内のレコードをすべて取得
  client.record.getAllRecords(params).then((resp) => {
    // 間違っても resp を console.log しない
    // タイムアウトで怒られる場合があります
    res.send(resp);
  }).catch((err) => {
    // エラーの場合はこっち
    res.send(err);
  });

};
```
フォルダ内のファイル構成はこんな感じ

```
.
├── node_modules
│   ├── @kintone
　〜 中略　〜
├── index.js
├── package-lock.json
└── package.json
```

## gcloud functions deploy
index.js の編集が終わったら、デプロイします。

VSCodeのターミナルでも良いので、下記のコマンドを打ちます。

```
gcloud functions deploy エントリポイント --runtime nodejs12 --trigger-http --allow-unauthenticated
```

下記のようなメッセージがターミナルに出たら、デプロイ完了（2分くらいかかります）。

```
status: ACTIVE
timeout: 60s
updateTime: '2021-02-04T13:31:42.989Z'
versionId: '1'
```

もし、下記のようなエラーが出たら

```
ERROR: (gcloud.functions.deploy) OperationError: code=7, message=Build failed: Cloud Build API has not been used in project 914641982874 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=プロジェクトコード then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
```

```
https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=プロジェクトコード
```

のURLを開いてみてください。

Google Build API とか言う画面が出てきますので、こちらを有効化してください。

![019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/b0f4bfc5-645b-1213-8a8c-35701fd87093.png)

## Google Cloud Functions でテスト
デプロイが完了したら、いよいよテストです。

ブラウザで再度GCPに入り、Google Cloud Functions を開くと...

![020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/ca5364c8-b60e-96c3-b791-6b0b3d39b8d1.png)
こんな画面になってます。

そしたら、
![021.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/5e33a513-c270-c3d1-92ec-dc3981d19eeb.png)
としてみましょう。

![022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/5bef95ae-5991-7ab4-8059-9937c3f74767.png)
上記画面になったら、迷わず青いボタンをクリックしてみてください。

すると…

![023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309897/e70db38c-56ad-31bd-d261-517ed92d3534.png)
出力結果をコピーして、VSCodeなんかで新しくJSONファイルを作り、ペーストします。

おそらくこんな感じになっているはず。

``` JSON
[
  {
    "like_code": {
      "type": "CHECK_BOX",
      "value": [
        "その他"
      ]
    },
    "レコード番号": {
      "type": "RECORD_NUMBER",
      "value": "1"
    },
    "更新者": {
      "type": "MODIFIER",
      "value": {
        "code": "レコードを追加した人のkintoneログインユーザー名",
        "name": "kintoneでレコードを追加した人の名前"
      }
    },
    "作成者": {
      "type": "CREATOR",
      "value": {
        "code": "レコードを追加した人のkintoneアカウント用",
        "name": "kintoneで"
      }
    },
    "name": {
      "type": "SINGLE_LINE_TEXT",
      "value": "最先 太郎"
    },
    "$revision": {
      "type": "__REVISION__",
      "value": "1"
    },
    "更新日時": {
      "type": "UPDATED_TIME",
      "value": "2021-02-04T12:04:00Z"
    },
    "作成日時": {
      "type": "CREATED_TIME",
      "value": "2021-02-04T12:04:00Z"
    },
    "email": {
      "type": "LINK",
      "value": "hogehatsukauna@exsample.com"
    },
    "$id": {
      "type": "__ID__",
      "value": "1"
    }
  },
  {
    "like_code": {
      "type": "CHECK_BOX",
      "value": [
        "FORTRAN",
        "COBOL"
      ]
    },
    "レコード番号": {
      "type": "RECORD_NUMBER",
      "value": "2"
    },
    "更新者": {
      "type": "MODIFIER",
      "value": {
        "code": "レコードを追加した人のkintoneアカウント用メールアドレス",
        "name": "kintoneでレコードを追加した人の名前"
      }
    },
    "作成者": {
      "type": "CREATOR",
      "value": {
        "code": "レコードを追加した人のkintoneアカウント用メールアドレス",
        "name": "kintoneでレコードを追加した人の名前"
      }
    },
    "name": {
      "type": "SINGLE_LINE_TEXT",
      "value": "kosan de waruika"
    },
    "$revision": {
      "type": "__REVISION__",
      "value": "1"
    },
    "更新日時": {
      "type": "UPDATED_TIME",
      "value": "2021-02-04T12:04:00Z"
    },
    "作成日時": {
      "type": "CREATED_TIME",
      "value": "2021-02-04T12:04:00Z"
    },
    "email": {
      "type": "LINK",
      "value": "exsample@hoge.com"
    },
    "$id": {
      "type": "__ID__",
      "value": "2"
    }
  },
  {
    "like_code": {
      "type": "CHECK_BOX",
      "value": []
    },
    "レコード番号": {
      "type": "RECORD_NUMBER",
      "value": "3"
    },
    "更新者": {
      "type": "MODIFIER",
      "value": {
        "code": "レコードを追加した人のkintoneアカウント用メールアドレス",
        "name": "kintoneでレコードを追加した人の名前"
      }
    },
    "作成者": {
      "type": "CREATOR",
      "value": {
        "code": "レコードを追加した人の",
        "name": "kintoneでレコードを追加した人の名前"
      }
    },
    "name": {
      "type": "SINGLE_LINE_TEXT",
      "value": " 遠山 景元"
    },
    "$revision": {
      "type": "__REVISION__",
      "value": "1"
    },
    "更新日時": {
      "type": "UPDATED_TIME",
      "value": "2021-02-04T12:07:00Z"
    },
    "作成日時": {
      "type": "CREATED_TIME",
      "value": "2021-02-04T12:07:00Z"
    },
    "email": {
      "type": "LINK",
      "value": "sakura_fubuki@minamimachibugyou.go.jp"
    },
    "$id": {
      "type": "__ID__",
      "value": "3"
    }
  }
]
```

と言った感じで、無事 GCP から kintone を叩いて、kintone からレコードを引っ張り出せました。

# 最後に注意
と、ここまでやってきましたが、このまま本番で使うとエントリポイント叩けば誰でもデータが見えてしまうので、Google Cloud Functions の方に認証をかけるなりして本番対応させないと大変なことになります。

# 参考リンク
ここまでの作業はまだまだほんの触りで、アプリやサービスサイトを作るにはまだまだ不足なことがたくさんあります。

特に、kintone関係は…

そのあたりはおいおい書いていこうと思いますが、下記サイトを参考にガリガリ進めていくと人類が進化します。

* [kintone JavaScript Client (@kintone/rest-api-client)](https://developer.cybozu.io/hc/ja/articles/900000767263)
* [上記のいじり方の一部](https://github.com/kintone/js-sdk/blob/master/packages/rest-api-client/docs/record.md)
* [kintone REST API一覧](https://developer.cybozu.io/hc/ja/articles/360000313406)
* [kintone REST API について (GET編)](https://qiita.com/RyBB/items/08cf511f1dbce6cf76bf)
* [kintone REST API について (POST編)](https://qiita.com/RyBB/items/94c13ca56887558bb227)