GASでサービスアカウントとしてデータ操作する方法

前提できなかったのですが、調べて実行した内容を記載しておきます。

## やりたかったこと
ユーザーに直接入力はさせたくなかったが、GASで列追加やデータ更新などの操作はできる状態を作りたい。
そのためにOAuth2.0での認証で操作させたいと考えました。

Googleの認証種類はこちらを参考
https://cloud.google.com/docs/authentication#strategies


## Oath認証とアクセストークンの取得

OAuth2 for Apps Scriptというライブラリを使用して認証していきます。
https://github.com/googleworkspace/apps-script-oauth2

`1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF`をライブラリのIDに入れて`OAuth2`を使用できるようにします。

続いてこちらのコードで認証部分を作成してきいます。
https://github.com/googleworkspace/apps-script-oauth2#1-create-the-oauth2-service

ファイルから呼んだ方が良いと思いますが、テスト実施で終わったので直接入力していました。

```js:認証コード
const PRIVATE_KEY= '';
const CLIENT_ID = '';
const CLIENT_EMAIL= '';

/**
 * Configures the spreadsheet service.
 */
function getSpreasheetService() {
  return OAuth2.createService("spreadsheet")
  .setTokenUrl("https://accounts.google.com/o/oauth2/token")
  .setClientId(CLIENT_ID)
  .setPrivateKey(PRIVATE_KEY)
  .setIssuer(CLIENT_EMAIL)
  .setPropertyStore(PropertiesService.getScriptProperties())
  .setScope("https://www.googleapis.com/auth/spreadsheets");
}
```

これでアクセストークンを取得するためには下記で実行可能です。

```js:アクセストークンの取得
const service = getSpreasheetService();
service.getAccessToken();
```


## Sheets API(v4)でデータの取得

下記の情報を参考に実施コードを作成します。
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get


```js:データ取得
function getSheet(){
  const spreadsheetId= '';
  const service = getSpreasheetService();

  const range = 'シート1!A1:C2';
  const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}`;

  const res = UrlFetchApp.fetch(url,{
    method: 'GET',
    headers:{
      "Authorization": 'Bearer ' + service.getAccessToken(),
      'content-type':'application/json'
      }
  });

  console.log(res.getContentText());
}
```
この内容で実行すると、ユーザーに権限がなくて、
サービスアカウントに権限付与したスプレッドシートのデータは取得できました。


## Sheets API(v4)でデータの更新

batchUpdateでの更新方法を記載します。
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate


```js:データの更新
function updateSheet(){
  const spreadsheetId= '12lQMoI5_YNmwhtcVvb248NBrwyfqRlq-OgLL6iu5KaU';

  const service = getSpreasheetService();

  const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values:batchUpdate`;

  const body = {
    "valueInputOption": "USER_ENTERED",
    "data": [
      {
        "range": "シート1!A1",
        "values": [
          [1, 2, 3]
        ],
      }
    ],
  };

  const res = UrlFetchApp.fetch(url,{
    'method': 'POST',
    'headers': {
      "Authorization": 'Bearer ' + service.getAccessToken(),
    },
    'payload': JSON.stringify(body),
    'contentType': 'application/json',
    "muteHttpExceptions" : true,
  });

  console.log(res.getContentText());
}
```

うまくいくとレスポンスとして下記が返ってきます。

```
{
  "spreadsheetId": "1E3wJW0MhAqe-gSumMekcsVegw3c9**********",
  "totalUpdatedRows": 1,
  "totalUpdatedColumns": 3,
  "totalUpdatedCells": 3,
  "totalUpdatedSheets": 1,
  "responses": [
    {
      "spreadsheetId": "1E3wJW0MhAqe-gSumMekcsVegw3c9**********",
      "updatedRange": "'シート1'!A1:C1",
      "updatedRows": 1,
      "updatedColumns": 3,
      "updatedCells": 3
    }
  ]
}
```

payloadって今までよくわかっていなかった(公式サイトちゃんと呼んでなかった)けど
リクエストのbodyのことなんですね。
contentTypeはbodyの形式を指定するってことかな？

`JSON.stringify()`でテキストにしないとエラーになったのと、
JSONにしたときに`contentType`でタイプを指定しないと実行ができなかったです。

GASのリクエストの理解も深まってよかった。