CDK workshop for TypeScriptをlocalstackでやるときにはまったこと


インターン先の業務でAWSを触ることになり、手始めにcdkのworkshopをやりながら何となく理解しようとした。

https://cdkworkshop.com/15-prerequisites.html

こういうものは、公式が用意してくれているんだからそれに従い進めていくのがふつうである。
しかし、自分は以前少しだけ遊んでいたLocalStackを使ってみたくなり、開発環境改善のための検証もかねて一通りやることにした。
なおworkshop中に出てくる、コンソール画面で動きているかどうか確かめるようなことはすべてスキップしている。

## 検証環境

Ubuntu 20.04 on WSL2

## 準備
まずはworkshopのPrerequisitesから進めて、必要なものをインストールする。
次にLocalstack、aws-cdk-localをそれぞれインストールする。
なお、Localstackは公式リポジトリからdocker-composeをコピペしてきて使ったので、dockerも入れるのを忘れずに！

https://docs.localstack.cloud/get-started/

https://github.com/localstack/aws-cdk-local

## TypeScript Workshop

ここからはドキュメントを見ながら進める。
まずはdocker-composeでlocalstackを立ち上げておく。

以降、workshopに出てくるcdkはcdklocalに置き換えて進める。
cdklocal bootstrapはdocker-composeでlocalstackを立ち上げるたびに実行する必要があるので注意。

基本的には問題なく進めることができたが、唯一はまったのが以下の章のhitcounterを作るやつ。

https://cdkworkshop.com/20-typescript/40-hit-counter.html

```lambda/hitcounter.js
const { DynamoDB, Lambda } = require('aws-sdk');

exports.handler = async function(event) {
  console.log("request:", JSON.stringify(event, undefined, 2));

  // create AWS SDK clients
  const dynamo = new DynamoDB();
  const lambda = new Lambda();

  // update dynamo entry for "path" with hits++
  await dynamo.updateItem({
    TableName: process.env.HITS_TABLE_NAME,
    Key: { path: { S: event.path } },
    UpdateExpression: 'ADD hits :incr',
    ExpressionAttributeValues: { ':incr': { N: '1' } }
  }).promise();

  // call downstream function and capture response
  const resp = await lambda.invoke({
    FunctionName: process.env.DOWNSTREAM_FUNCTION_NAME,
    Payload: JSON.stringify(event)
  }).promise();

  console.log('downstream response:', JSON.stringify(resp, undefined, 2));

  // return response back to upstream caller
  return JSON.parse(resp.Payload);
};
```

workshopで上のように書かれているコードを、以下のように書き換える。

```diff:lambda/hitcounter.js
const { DynamoDB, Lambda, Endpoint } = require('aws-sdk');

+ const endPoint = new Endpoint(`http://${process.env.LOCALSTACK_HOSTNAME}:4566`);

exports.handler = async function(event) {
  console.log("request:", JSON.stringify(event, undefined, 2));

  // create AWS SDK clients
-   const dynamo = new DynamoDB();
-   const lambda = new Lambda();
+   const dynamo = new DynamoDB({ endpoint: endPoint });
+   const lambda = new Lambda({ endpoint: endPoint });

  // update dynamo entry for "path" with hits++
  await dynamo.updateItem({
    TableName: process.env.HITS_TABLE_NAME,
    Key: { path: { S: event.path } },
    UpdateExpression: 'ADD hits :incr',
    ExpressionAttributeValues: { ':incr': { N: '1' } }
  }).promise();

  // call downstream function and capture response
  const resp = await lambda.invoke({
    FunctionName: process.env.DOWNSTREAM_FUNCTION_NAME,
    Payload: JSON.stringify(event)
  }).promise();

  console.log('downstream response:', JSON.stringify(resp, undefined, 2));

  // return response back to upstream caller
  return JSON.parse(resp.Payload);
}; 
```
これでとりあえずworkshopを一通り終えることができた。

## おわりに
実はlocalstack用のawscliというのもある。
これも併用すると、ローカルでの開発がはかどるだろう。

https://github.com/localstack/awscli-local

また、workshopを行ったリポジトリを以下においているので、もし追加したことがあればPRなど送ってくれるとうれしい。

https://github.com/nakano16180/cdk-workshop