AWS Lambdaでaws-sdkが見つからないエラーを解決

今回は、LambdaとAPI Gatewayを組み合わせて、DynamoDBにデータを登録する仕組みを作ろうと実践してみました。
ところが、実際にLambda関数を実行してみたところ、まさかの「aws-sdkが見つからない」というエラーが発生。
Node.jsのランタイムバージョンを22や18に変更して再試行したり、Lambdaの権限を確認するなど、さまざまな解決方法を試してみましたが、状況は改善せず…。

そんな中、「ローカル環境にaws-sdkをインストールする」という解決策を見つけ、これを試したところ無事に問題を解決しました。
同じような状況でお困りの方の参考になればと思い、今回の手順をまとめました。


以下は実際にテストした際のソースコードです。
```index.js
const AWS = require('aws-sdk');

// DynamoDB クライアントを作成
const dynamoDb = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event) => {
    try {
        const version = AWS.VERSION; // AWS SDK のバージョンを取得
        return {
            statusCode: 200,
            body: JSON.stringify({
                message: "aws-sdk is available!",
                version: version,
            }),
        };
    } catch (error) {
        return {
            statusCode: 500,
            body: JSON.stringify({
                message: "aws-sdk is not available",
                error: error.message,
            }),
        };
    }
};
```
実行結果（エラーレスポンス）
```
Status: Failed
Test Event Name: test

Response:
{
  "errorType": "Runtime.ImportModuleError",
  "errorMessage": "Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs",
  "trace": [
    "Runtime.ImportModuleError: Error: Cannot find module 'aws-sdk'",
    "Require stack:",
    "- /var/task/index.js",
    "- /var/runtime/index.mjs",
    "    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)",
    "    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)",
    "    at async start (file:///var/runtime/index.mjs:1282:23)",
    "    at async file:///var/runtime/index.mjs:1288:1"
  ]
}

Function Logs:
2024-12-05T04:51:04.621Z	undefined	ERROR	Uncaught Exception 	{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs","stack":["Runtime.ImportModuleError: Error: Cannot find module 'aws-sdk'","Require stack:","- /var/task/index.js","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)","    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)","    at async start (file:///var/runtime/index.mjs:1282:23)","    at async file:///var/runtime/index.mjs:1288:1"]}
INIT_REPORT Init Duration: 1369.04 ms	Phase: invoke	Status: error	Error Type: Runtime.ImportModuleError
START RequestId: 61c5f896-c8b0-4e42-ae88-7e35bc7caf21 Version: $LATEST
END RequestId: 61c5f896-c8b0-4e42-ae88-7e35bc7caf21
REPORT RequestId: 61c5f896-c8b0-4e42-ae88-7e35bc7caf21	Duration: 1379.37 ms	Billed Duration: 1380 ms	Memory Size: 128 MB	Max Memory Used: 65 MB	Status: error	Error Type: Runtime.ImportModuleError

Request ID: 61c5f896-c8b0-4e42-ae88-7e35bc7caf21
```

# はじめに

今回私の環境はMacOSなので、Windowsをお使いの方には少し手順が異なるかもしれません。その点はご了承いただければと思います。

まずは、aws-sdkをインストールする前に、必要な準備についてご紹介します。

今回、aws-sdk のインストールには npm コマンドを使用します。そのため、まずは npm をインストールする必要があります。
npm のインストール方法には、主に以下の2つの方法があります。

・Homebrewを使ってインストールする方法
・公式サイトから直接インストールする方法

## Homebrewを使ってインストールする方法
自分は今回こちらの方法でインストールを実施しました
Homebrewがインストールされていない場合は下記コマンドを実行します。
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
その後、Node.jsをインストールします。
```
brew install node
```
その後、インストールしたNode.jsとnpmのバージョンが表示されればインストール成功です。
```
node -v
npm -v
```

## 公式サイトから直接インストールする方法
https://nodejs.org/

公式サイトにアクセスし、「LTS（推奨版）」を選択して画面の指示に従ってダウンロードします。
その後、同じようにターミナルで以下コマンドを実行してバージョンが表示されればインストール成功です。
```
node -v
npm -v
```
これでnpmコマンドが使用できるようになりました！
# AWS SDKインストール
次にAWS SDKをインストールしましょう。
まず作業フォルダを作成します。
```
mkdir aws-sdk-layer
cd aws-sdk-layer
mkdir nodejs
cd nodejs
```
npmコマンドでSDKインストールします
```
npm install aws-sdk
```
これで、nodejs フォルダ内に node_modules フォルダが作成され、AWS SDK がインストールされます。
次に一つ前の階層に戻ってZIPファイルを作成します。
```
cd ..

zip -r aws-sdk-layer.zip nodejs
```
作業フォルダに aws-sdk-layer.zip というファイルが作成されます。

# レイヤー作成
続いて、Lambda コンソールを開き、左側のメニューから「レイヤー」を選択し、右上にある「レイヤーの作成」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952109/bd92cd6c-dc36-ee0a-f22f-4bcc9506893a.png)

名前を入力し、ファイルをアップロードします。
今回アップロードしたいファイルは10MBを超えるため、S3 に「aws-sdk-layer.zip」 をアップロードし、そこから指定するのがおすすめです。
S3にアップロード後、ZIPファイルのオブジェクトURLをコピーし、アップロードに使用します。

ランタイムの設定
「互換性のあるランタイム」には、Lambdaで使用しているランタイムと同じバージョンを選択します。
今回は Node.js 18.x を使用しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952109/c146bb01-587a-fd58-3ec5-8d0b63a922d9.png)

レイヤーを作成したら、バージョンARNをコピーしておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952109/e6438701-598f-baa9-e981-c5788b9ff4c2.png)

# Lambda関数にレイヤーを追加

最後に、作成したLambda関数にレイヤーを追加します。
対象のLambda関数を選択し、画面をスクロールして「レイヤー」の項目まで進みます。そこで、右側にある「レイヤーの追加」をクリックしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952109/be6f2a49-4c53-210b-80d3-fdeacec2ac67.png)


ここで「ARNを指定」を選択します。
「AWS レイヤー」の項目に、先ほどコピーしたバージョンARNを貼り付け、右下の「追加」ボタンをクリックしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952109/1be97843-6601-e25b-3c8d-3e843157c491.png)

これで設定は完了です。最後に、Lambda関数を再デプロイしてテストを実行してみましょう。

```
Status: Succeeded
Test Event Name: test

Response:
{
  "statusCode": 200,
  "body": "{\"message\":\"aws-sdk is available!\",\"version\":\"2.1692.0\"}"
}

Function Logs:
START RequestId: b9df522e-ba5c-4703-9d64-2ba3f7d03957 Version: $LATEST
END RequestId: b9df522e-ba5c-4703-9d64-2ba3f7d03957
REPORT RequestId: b9df522e-ba5c-4703-9d64-2ba3f7d03957	Duration: 117.78 ms	Billed Duration: 118 ms	Memory Size: 128 MB	Max Memory Used: 92 MB	Init Duration: 755.95 ms

Request ID: b9df522e-ba5c-4703-9d64-2ba3f7d03957
```

このようにレスポンスが正常に返ってくれば、設定は成功です。
ぜひ参考にしていただければと思います。