HTTPトリガーにより Azure Functions から Google Spreadsheets に書き込み その1

# 概要
何らかのトリガー（とりあえず HTTPトリガーを想定 ）により起動した **Azure Functions (v2)**（=Auzre Function App）の内部から **Google Spreadsheets** のセルに書き込みをする方法についてまとめました。専用のライブラリは使わずにRESTで**Google Sheets API v4**を操作する方法で実装しました。

モノ → IoTデバイス → Azure Functions → Google Spreadsheets のような連携で、モノに対する操作を行なった時刻などを記録していくことを想定しています。

このエントリは、**準備編**ということで、GoogleSheetsAPI を利用するために必要な各種キーの取得手順と、それを使ってローカルなプログラム（C#）から GoogleSpreadsheets にデータを書き込むテストについて紹介・説明をします。


# 準備

GoogleSheetsAPI を通じて [Google Spreadsheets](https://docs.google.com/spreadsheets/u/0/) の書き替えを行なうためには、次の操作と情報と必要になります。

1. APIに付与する権限の許可操作（ブラウザ画面からのユーザ操作）
2. 書き込み対象のシートのID `SheetId`
3. クライアントID `client_id`
4. クライアントシークレット `client_secret`
5. アクセストークン `access_token`
6. リフレッシュトークン `refresh_token`

以下は、これらの情報を取得する方法についての記録です。
なお、Googleアカウントにログインしている状態で操作することを前提とした説明となっています。

## シートIDの取得

[Google Spreadsheets](https://docs.google.com/spreadsheets/u/0/) にアクセスします。
シートを新規作成して、セル適当な値を書き込むとシートがオートセーブされます。セーブされたら、この**シートのID**をメモしておきます。シートIDはブラウザのURL欄から確認することができます。シートを新規作成してからセルに何も書き込まずに「戻る」をすると、シートは消えてメモしたIDも無効になってしまうので注意します。

![2019-02-21_08h40_59.png](https://qiita-image-store.s3.amazonaws.com/0/152805/5c577187-dae6-a8c3-8485-764c80c040d8.png)

## クライアントIDとクライアントシークレットの取得

[GoogleSheets API v4 .NET Quickstart](https://developers.google.com/sheets/api/quickstart/dotnet) にアクセスします。
「Step 1: Turn on the Google Sheets API」の「**ENABLE THE GOOGLE SHEETS API**」のボタンをクリックして・・・

![2019-02-21_08h50_10.png](https://qiita-image-store.s3.amazonaws.com/0/152805/356374ca-09ec-d123-af6f-a05242cca2e5.png)


表示されるダイアログから**クライアントID**と**クライアントシークレット**を確認し、メモしておきます。また「**DOWNLOAD CLIENT CONFIGURATION**」をクリックして`credentials.json`をダウンロードしておきます。`credentials.json`のなかにも**クライアントID**と**クライアントシークレット**が記載されています。

なお、「ENABLE THE GOOGLE SHEETS API」をクリックするたびに、クライアントIDとクライアントシークレットは更新されます。最新のものを使うようにしてください。

![2019-02-21_08h51_43.png](https://qiita-image-store.s3.amazonaws.com/0/152805/868e2a0a-cfa8-eeb8-a16c-bf709f65c52c.png)

## 権限付与の許可操作とアクセストークンとリフレッシュトークンの取得

**アクセストークン**と**リフレッシュトークン**を取得するためには、ブラウザ上に「API権限付与の確認画面」を出力して、ユーザ操作により許可を与える必要があります。これは、初回のみ必要な手続きなのですが、AzureFunction上で実行させるとなると面倒なので、ローカルのプログラムでそれを実行して、あらかじめアクセストークンとリフレッシュトークンを取得しておきます。

ローカルで実行するためのプログラムは、[GoogleSheets API v4 .NET Quickstart](https://developers.google.com/sheets/api/quickstart/dotnet)の「Step 3: Set up the sample」に掲載されているサンプルを、ほぼそのまま利用できます。このサンプルプログラムは「**指定したスプレッドシートのセルの中身をAPIを通じて読み取ってきて出力するサンプル**」となっています。

最終的には少しだけコードの変更が必要なのですが、まずは、サンプルをそのまま Visual Studio 2017 に持ってきてビルド・実行します。以下、その手順です。

- Visual Studio 2017 を起動して「ファイル」―「新規作成」―「プロジェクト」で「コンソール アプリ（.NET Framework）C#」を選択します。
- `Program.cs`に、Step 3に掲載されている`sheets/SheetsQuickstart/SheetsQuickstart.cs`をそのまま貼付けします。
- メニューから「ツール」―「NuGetパッケージマネージャ」―「パッケージマネージャコンソール」を選択して、コンソールで`Install-Package Google.Apis.Sheets.v4`と打ってエンターを押します。
- メニューから「ビルド」―「ソリューションのビルド」を実行します（エラーがないことを確認します）。
-  先ほどダウンロードした`credentials.json`を実行フォルダにコピーします。

![2019-02-21_09h15_11.png](https://qiita-image-store.s3.amazonaws.com/0/152805/a4ecf7cd-39e4-edc4-97d0-1cddf3ac925e.png)

- Visaul Studio に戻って、メニューから「デバッグ」―「デバッグの開始」を実行します。
- 自動的にブラウザが起動して、Googleのアカウントの選択画面が表示されるのでアカウントを選択、次に「Quickstartへの権限付与」というダイアログが表示されるので「許可」を選択、さらに「選択内容を確認してください」のダイアログが表示されるので「許可」を選択します。

![2019-02-21_09h18_08.png](https://qiita-image-store.s3.amazonaws.com/0/152805/b4706146-2afc-d7c3-6b95-41fd6cb84313.png)

![2019-02-21_09h21_03.png](https://qiita-image-store.s3.amazonaws.com/0/152805/aa8fa89e-9e19-e72f-be0e-3cc3256700d9.png)

- 許可を与えると、実行しているプログラムから次のような内容が出力されます（プログラムのなかで指定されている[サンプルシート](https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit#gid=0)の内容を読み取ってきて出力しています）。エンターを入力するとプログラムは終了します。

![2019-02-21_09h24_33.png](https://qiita-image-store.s3.amazonaws.com/0/152805/070510dd-f73d-5c11-9cc6-60a84ad6c896.png)

- プログラムの実行フォルダを確認すると、`token.json`というフォルダが作成されていて、さらに、そのなかに`Google.Apis.Auth.OAuth2.Responses.TokenResponse-user`というファイルがつくられています。これを適当なエディタで開くと*アクセストークン*と*リフレッシュトークン*が確認できます。また、権限が `"scope":"https://www.googleapis.com/auth/spreadsheets.readonly"` となっていることが確認できます。

![2019-02-21_09h42_56.png](https://qiita-image-store.s3.amazonaws.com/0/152805/47d05a26-b469-b3dc-e12d-adb53e2b3851.png)

- `spreadsheets.readonly`という権限（スコープ）では、セルに対する書き込み操作ができないので手を加えていきます。サンプルプログラムの上部でスコープを設定している部分があるので、それを次のように書き換えます。

```CSharp:変更前
static string[] Scopes = { SheetsService.Scope.SpreadsheetsReadonly };
```

```CSharp:変更後
static string[] Scopes = { SheetsService.Scope.Spreadsheets };
```

- 上記を書き換えたら `token.json`フォルダを**一旦、削除してから**、プログラムを、再度、ビルドして実行します。
- 今度は、編集権も含めた権限付与の確認画面がでるので許可を与えます。権限の項目が「スプレッドシートの表示、**編集**、作成、削除」になっていることが確認できます。

![2019-02-21_09h21_03.png](https://qiita-image-store.s3.amazonaws.com/0/152805/187a435f-3d50-8e3b-d872-7a3b85008e1d.png)

以上で、スプレッドシートの編集も可能な**アクセストークン**と**リフレッシュトークン**を入手できました（`token.json`フォルダの`Google.Apis.Auth.OAuth2.Responses.TokenResponse-user`を参照）。

せっかくなので、ローカルプログラムでもスプレッドシートの書き替えをしてみます。対象のシートを自分が所有するシートに変更して、そこに値を書き込んでいきます。

```CSharp:変更前
// Define request parameters.
String spreadsheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms";
String range = "Class Data!A2:E";
SpreadsheetsResource.ValuesResource.GetRequest request =
    service.Spreadsheets.Values.Get(spreadsheetId, range);

// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
ValueRange response = request.Execute();
IList<IList<Object>> values = response.Values;
if (values != null && values.Count > 0) {
    Console.WriteLine("Name, Major");
    foreach (var row in values) {
        // Print columns A and E, which correspond to indices 0 and 4.
        Console.WriteLine("{0}, {1}", row[0], row[4]);
    }
} else {
    Console.WriteLine("No data found.");
}
Console.Read();
```


```CSharp:変更後
// Define request parameters.
String spreadsheetId = "{シートID}";
String range = "A1";
ValueRange valueRange = new ValueRange() { MajorDimension = "ROWS" };
valueRange.Values = new List<IList<object>>();
valueRange.Values.Add(new List<object>() { "2019/01/20", 10, "Neko" });
valueRange.Values.Add(new List<object>() { "2019/01/21", 12, "Inu" });
var request = service.Spreadsheets.Values.Update(valueRange, spreadsheetId, range);
request.ValueInputOption = SpreadsheetsResource.ValuesResource.UpdateRequest.ValueInputOptionEnum.USERENTERED;
var res = request.Execute();
Console.Read();
```

書き換えたプログラムを実行して、スプレッドシートを開いてみるとセルが指定した内容に書き換えられていることが確認できます。

![2019-02-21_10h25_04.png](https://qiita-image-store.s3.amazonaws.com/0/152805/7a7b0ec5-3ded-af0e-c98f-6bbf3d41fd6e.png)

# 次回は・・・

**Azure Functions**から**Google Spreadsheets**に書き込むための本編になります。

- [HTTPトリガーにより Azure Functions から Google Spreadsheets に書き込み その2](https://qiita.com/code0327/items/0790caf49243f64ce157)