GASでAWSリソースにアクセスするために

## はじめに

とある事情からスプレッドシートをフロントエンドとしてLambdaで処理を行い生成物をGoogle Drive上に保存するシステムを実装する際にすごく悩んだので備忘録として残しておきます。

今回のシステム構成は以下のような構成でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/0b0e245a-e93b-b011-50b4-618680718893.png)

シリアルに処理を実行すると、スプレッドシートの1行を単位で処理するため60分程かかります。
GASの制約としては6分、Lambdaは15分のため何かしら工夫が必要でした。

他のチームメンバだとAPI GatewayでREST API経由で実行したり、S3にファイルを保存したイベントでLambdaを実行していましたが、実行頻度も少ないことと、イベント発火させるためだけにS3にファイルを置くのが無駄だよねということでEventBridge のPutEvents を契機に処理する方針としました。

実績のないこの方針は、AWSナニモワカラナイマンとしてはかなり辛かった。。。orz

## GASからAWSリソースへアクセスするために

AWS sdkではいろいろな言語をサポートしていてsdkが使えさえすればACCESS KEY SECRET KEYを作成すれば簡単にアクセスすることができます。

ですが、GASからとなるとAWS sdk がインストールできるわけではないので工夫する必要があります。

GASからAWSへアクセスするのを検索すると何点かヒットします。

最初に試したのがこちら。
https://developer.mamezou-tech.com/blogs/2023/06/28/gas-using-npm-packages/

言っていることはわかる。
でもどのようにGASへ読み込ますなどがピンと来ず断念。

次に試したのがこちら。
https://akkinoc.dev/posts/2022/05/15/aws-api-from-google-apps-script/

使用するのは [こちら](https://github.com/smithy545/aws-apps-scripts) のGitHub上にあるaws.js というファイルをコピって貼り付けるだけ。
簡単にGASからAWSリソースにアクセスすることができました。
知識を供していただけたこと、素晴らしいスクリプトを公開していただき本当にありがとうございます。

次の課題としては、パラメータをどのように設定するか🤔

## aws.jsのパラメータ設定について

上記のページでaws cliをdebugで実行してみるとわかるよということで試してみました。
いきなり最終系ですが、PutEventsを送るには以下のようなGASのコードになります。

```javascript
  AWS.init(key.accessKey, key.secretKey);

  const obj = {
    Entries: [{
      Source: 'hogehoge',
      DetailType: 'fugafuga',
      Detail: JSON.stringify({
        sheetId : "123456789"
      })
    }]
  };

  const res = AWS.request("events",
                            "ap-northeast-1",
                            "AWSEvents.PutEvents",
                            {},
                            "POST",
                            obj,
                            {"Content-Type": "application/x-amz-json-1.1"});
  console.log(res.getContentText());
```

ここでの引っかかりポイントは `Detail` の部分にJavaScriptのオブジェクトをそのまま設定しちゃいけないというところです。

`Detail` 部分にそのままオブジェクトを設定すると、以下のようなエラーが返ってきます。

```
	{"__type":"SerializationException","Message":"Start of structure or map found where not expected."}
```

最初、一体どこの部分のことを言っているんだ。。。？と。
[ユーザガイド](https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-putevents.html#eb-send-events-aws-cli) を何回も読みふと気がついたことで、`Detail` をよく見るとjsonオブジェクトじゃなく文字列になっているじゃんと。

ということで `Detail` をstringifyして設定することで無事イベント登録することができました。
成功すると、以下のようなログが出力されます。

```
{"Entries":[{"EventId":"079ceaa5-b673-aecd-c815-b6202c2edf8e"}],"FailedEntryCount":0}
```

## EventBridgeとStep Functions をつなぐために

イベントは正しく登録できたっぽい。
ただし、EventBridgeのモニタリングにもCloudWatch Logsにも何も出てこない。
ホントに正しく登録できているのか。。。🤔というのに3日位悩みました。
ログ的なものは何も残ってないけど、APIKEYの `Last used` は変わっているのでAWSの世界には来てるんだろうと信じて、とりあえずつなぐ部分を進めてみました。

まずはEventBridgeでルールを作ろう。
ここは問題ないだろう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/47c2e21b-f94e-fefa-b469-43fa30696234.png)

ひっかかったのは次のページ。
イベントソースはAWSのイベントを契機にするので一番上でOK。
次のSample event はoptional と書いてあるので無視。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/70e59ab2-798e-9d5a-2ceb-2cf46da5c835.png)

ここからがよく分からなかった。
今回はEventBridge のPutEvents を設定したいのに表示されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/5a95cf1c-04b1-f07a-d842-263b7eb295af.png)

とりあえず `All Events` にすれば良いのかと選択すると、以下のようなパターンが設定される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/356a0531-d8df-d884-7f25-bcf5caf75664.png)

この `source` というのはどこのことを指しているんだ。。。🤔とモヤモヤしつつ進め、ターゲットにStep Functions を設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/582de4ce-220b-b668-96bb-1e929306659f.png)

これでルールができたのでGASから実行してもStep FunctionsのExecutionsのところにイベントが増えない。
※ 以下の画像はすでに繋がっているためいっぱいあります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/29b081d8-4d96-25f3-50a8-b3121d7c7949.png)

イベントに登録できているのにルールに引っかかっていないためイベントが破棄されてそう。
イベントパターンに全部のイベント引っかかるようにしているはずなのになぜ？というところで悩みまくっていました。

色々考えた挙げ句、イベントパターンの部分をよくよく見てみると `Prefix matching` とかいくつかあります。
もしかしてさっき `source` の部分に `[aws.events]`とか設定したけど、これ自体がGASで設定しているオブジェクトの `Entries` のフィルタなのでは？思いつきやってみたところビンゴ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65929/9f96a704-4bf3-f49c-df36-4e067ebe6d05.png)

完全一致ではないのね。。。と思いつつなんとか繋がってホッとしました。

## おわりに

これでGASからの連携でAPI Gatewayを建てなくても良いし、無駄にS3にファイルを置かなくてもPOSTのパラメータだけでAWSリソースにアクセスすることができました。

自分なりに色々探してみたけどみんな普通はどうやるんだろう。。。という部分はモヤモヤしたままですが、目的を達成できてとりあえず満足。

ここまでお付き合いしていただきありがとうございます。