背景
・AWS CDK Workshop(TypeScriptワークショップ)に取り組んでいる中で、Lambdaのランタイム(Node.js)のバージョンによる差異がありコードの修正が必要だったのでその備忘です
・ワークショップはNode.js 14.xになっていますが、現在Lambdaでは14.xはサポートされていないため20.xにしたところエラーが発生し上手くいきませんでした
対象箇所
Node.js 20.xでやりたい場合にコードを修正する必要があった作業箇所です
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);
};
20.xでこのままやってみると、
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/hitcounter.js\n- /var/runtime/index.mjs",
"stack": [
"Runtime.ImportModuleError: Error: Cannot find module 'aws-sdk'",
このようなエラーになりました。
14.xではSDKのバージョンが2になっていますが、20.xの場合はSDKのバージョンが3になっているためその差異による修正が必要になります
修正内容
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { LambdaClient, InvokeCommand } from "@aws-sdk/client-lambda";
export const handler = async function (event) {
console.log("request:", JSON.stringify(event, undefined, 2));
// create AWS SDK clients
const dynamo = new DynamoDBClient({});
const lambda = new LambdaClient({});
// update dynamo entry for "path" with hits++
const dynamoInput = {
TableName: process.env.HITS_TABLE_NAME,
Key: { path: { S: event.path } },
UpdateExpression: "ADD hits :incr",
ExpressionAttributeValues: { ":incr": { N: "1" } },
};
const dynamoCommand = new UpdateItemCommand(dynamoInput);
await dynamo.send(dynamoCommand);
// call downstream function and capture response
const lambdaInput = {
FunctionName: process.env.DOWNSTREAM_FUNCTION_NAME,
Payload: JSON.stringify(event),
};
const lambdaCommand = new InvokeCommand(lambdaInput);
const lambdaResponse = await lambda.send(lambdaCommand);
const result = Buffer.from(lambdaResponse.Payload).toString();
console.log("downstream response:", result);
// return response back to upstream caller
return JSON.parse(result);
};
必要な変更点は以下でした
・SDKのバージョンアップによる変更(requireからimportへの変更、APIの変更や処理の仕方の変更)
・ESモジュールに対応させるための変更(.jsから.mjsへの変更、exportの仕方の変更)
修正内容までの流れ
まずは修正前に20.xでやった場合に出たSDK関連のエラーに対する、SDKのバージョンアップの対応をしました。
requireからimportへの変更、APIの変更や処理の仕方の変更です
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { LambdaClient, InvokeCommand } from "@aws-sdk/client-lambda";
exports.handler = async function(event) {
console.log("request:", JSON.stringify(event, undefined, 2));
// create AWS SDK clients
const dynamo = new DynamoDBClient({});
const lambda = new LambdaClient({});
// update dynamo entry for "path" with hits++
const dynamoInput = {
TableName: process.env.HITS_TABLE_NAME,
Key: { path: { S: event.path } },
UpdateExpression: "ADD hits :incr",
ExpressionAttributeValues: { ":incr": { N: "1" } },
};
const dynamoCommand = new UpdateItemCommand(dynamoInput);
await dynamo.send(dynamoCommand);
// call downstream function and capture response
const lambdaInput = {
FunctionName: process.env.DOWNSTREAM_FUNCTION_NAME,
Payload: JSON.stringify(event),
};
const lambdaCommand = new InvokeCommand(lambdaInput);
const lambdaResponse = await lambda.send(lambdaCommand);
const result = Buffer.from(lambdaResponse.Payload).toString();
console.log("downstream response:", result);
// return response back to upstream caller
return JSON.parse(result);
};
これでやってみると、
"errorType": "Runtime.UserCodeSyntaxError",
"errorMessage": "SyntaxError: Cannot use import statement outside a module",
"stack": [
"Runtime.UserCodeSyntaxError: SyntaxError: Cannot use import statement outside a module",
今度は違うエラーになりました。
上記のSDKのバージョンアップの対応でimportを利用しているのでESモジュールとして扱わないといけないのですが、.jsはCommonJSモジュールとして扱われるため、.jsから.mjsとするとESモジュールとして扱われるようになります。
また、ESモジュールの場合でexportの仕方が変わるのでそれも変更すると、最終的に修正内容の形になり、無事エラーなく実行できるようになりました
参考