GASのExcel版、Office Scriptで外部APIを触るまでメモ


デスクトップ版のExcelだとVBAがありますが、Web版のExcelだとOffice Scriptが使える模様です。
ただし、Office365の有償ライセンスが必要みたいです。

SpreadSheetとGASの関係に近い気がしていて、GASのExcel版だと思って大丈夫だと思います。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">GASは便利だけどGoogleサービスにPower Automate的なiPaaSがあると便利なのかも<br><br>Excel &lt;-&gt; SpreadSheet<br>Office Script &lt;-&gt; GAS<br>Power Apps &lt;-&gt; App Sheet<br>Power BI &lt;-&gt; Looker Studio<br>Power Automate &lt;-&gt; (ここがない気がする)<a href="https://twitter.com/hashtag/gas?src=hash&amp;ref_src=twsrc%5Etfw">#gas</a> <a href="https://twitter.com/hashtag/powerautomate?src=hash&amp;ref_src=twsrc%5Etfw">#powerautomate</a></p>&mdash; 菅原のびすけ (@n0bisuke) <a href="https://twitter.com/n0bisuke/status/1591444093590450179?ref_src=twsrc%5Etfw">November 12, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 始め方

Excelのメニューに自動化という項目があるので選択して、新しいスクリプトからエディタを開けます。

> ![スクリーンショット 2022-11-13 13.07.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/00d016e8-4d72-af6b-6053-82838cd00b5e.png "スクリーンショット 2022-11-13 13.07.37.png")


コードエディタが立ち上がるので、以下を書いて実行してみます。


```ts
function main(workbook: ExcelScript.Workbook) {
  let selectedSheet = workbook.getActiveWorksheet();
  selectedSheet.getRange("A2:B2").getFormat().getFill().setColor("FFC000");
}
```

> ![スクリーンショット 2022-11-13 13.04.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/cd4cffb6-3a7b-a184-0184-0ce77df35b6d.png "スクリーンショット 2022-11-13 13.04.41.png")


セルの色が変われば成功です。


- セルの取得

```ts
function main(workbook: ExcelScript.Workbook) {
    // Your code here
    // 現在のシートを取得
    let activeSheet = workbook.getActiveWorksheet();
    // 1つ目のシートを取得
    let firstSheet = workbook.getWorksheets()[0];
    // A1からB2の範囲を取得
    let range1 = activeSheet.getRange('A1');
    let range2 = activeSheet.getRange('B2');
    // 現在のシート名をログ出力
    console.log(range1.getValue(), range2.getValue());
}
```

A1とB2から取得します。 複数の場合`getRange('A1:B2');`などにすると取れてその場合`getValue()`ではなく`getValues()`で取得したりします。ものすごくGASの関数に似てますね。

> ![スクリーンショット 2022-11-13 13.13.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/8b1dd035-b659-850b-c62d-b483cd1a452c.png "スクリーンショット 2022-11-13 13.13.54.png")

## エラー出力

画面下のコンソールにエラーは表示される模様です。

> ![スクリーンショット 2022-11-13 13.17.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/097a7687-b21d-70cf-e539-65d1ec029546.png "スクリーンショット 2022-11-13 13.17.37.png")

## 外部APIの利用

GASでは`UrlFetchApp`を使ってHTTPクライアントを作れましたが、Office Scriptでは[Fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API)が使える模様です。

> https://learn.microsoft.com/ja-jp/office/dev/scripts/resources/samples/external-fetch-calls?source=recommendations

公式ドキュメントサンプル通りですが、[n0bisuke](https://github.com/n0bisuke)のGitHub公開リポジトリを取得してみます。

```ts
async function main(workbook: ExcelScript.Workbook) {
  // Call the GitHub REST API.
  // Replace the {USERNAME} placeholder with your GitHub username.
  const response = await fetch('https://api.github.com/users/n0bisuke/repos');
  const repos: Repository[] = await response.json();

  // Create an array to hold the returned values.
  const rows: (string | boolean | number)[][] = [];

  // Convert each repository block into a row.
  for (let repo of repos) {
    rows.push([repo.id, repo.name, repo.license?.name, repo.license?.url]);
  }
  // Create a header row.
  const sheet = workbook.getActiveWorksheet();
  sheet.getRange('A1:D1').setValues([["ID", "Name", "License Name", "License URL"]]);

  // Add the data to the current worksheet, starting at "A2".
  const range = sheet.getRange('A2').getResizedRange(rows.length - 1, rows[0].length - 1);
  range.setValues(rows);
}

// An interface matching the returned JSON for a GitHub repository.
interface Repository {
  name: string,
  id: string,
  license?: License
}

// An interface matching the returned JSON for a GitHub repo license.
interface License {
  name: string,
  url: string
}
```

> ![スクリーンショット 2022-11-13 13.34.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/9deebae0-b4f2-e92e-06e4-c40c5273b8fd.png "スクリーンショット 2022-11-13 13.34.54.png")


## Power Automate経由でのHTTPリクエストはできない模様

HTTPリクエストできるならPower Automateからフックさせて自由にやれそう？って思ったけどちゃんとブロックされてましたね。。残念。

> https://learn.microsoft.com/ja-jp/office/dev/scripts/develop/external-calls
> スクリプトがPower Automateで実行されると、外部 API 呼び出しは失敗します。 

とのことです。

## doGet()やdoPost()はなさそう

GASのようにdoGet()を使ってサーバーの立ち上げができたら面白いなと思いましたが、パッと調べた感じそこはなさそうな雰囲気でした。

できるよーって話あればコメントくださいませ。


## 使ってみた所感

若干動きがもっさりする印象です。実行ボタンを押してから表示されるまでの挙動に少し重さを感じます。(GAS比較)

### 歯痒さある

最近のGASはHTTPクライアントもサーバーも作れて自由度が高いですが、Office Scriptはクライアントのみ+PAからの外部トリガー起動ができなさそうな雰囲気でした。

### TypeScriptなのは良い

MSだからってのもあるとは思いますが、GASと違ってTypeScriptを採用しているのは（たぶん）後発の強みを感じます。

### よくわからんエラーがたまにでるのが辛い

通常だとこのような挙動ですが、よくわからないエラーが永遠に表示される時があります。

`問題が発生しました。 ページを更新するか、Office スクリプト ウィンドウをもう一度開いてください。` というメッセージですね。

> ![スクリーンショット 2022-11-13 13.22.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/02942014-f933-f079-7082-3e77c47c9c8d.png "スクリーンショット 2022-11-13 13.22.05.png")

再読み込みすると解消しますが気持ち悪い。

ちょっとしか使ってないですが、ここが1番使っててしんどいなと思いました。

今後に期待ですね。

## 参考

- https://forest.watch.impress.co.jp/docs/news/1328019.html
- https://dev.classmethod.jp/articles/office-scripts-available-in-excel-web/