1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS CDK Workshop(TypeScript)をNode.js 20.xでやりたい場合

Posted at

背景

・AWS CDK Workshop(TypeScriptワークショップ)に取り組んでいる中で、Lambdaのランタイム(Node.js)のバージョンによる差異がありコードの修正が必要だったのでその備忘です
・ワークショップはNode.js 14.xになっていますが、現在Lambdaでは14.xはサポートされていないため20.xにしたところエラーが発生し上手くいきませんでした

対象箇所

Node.js 20.xでやりたい場合にコードを修正する必要があった作業箇所です

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);
};

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になっているためその差異による修正が必要になります

修正内容

lambda/hitcounter.mjs
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の変更や処理の仕方の変更です

lambda/hitcounter.js
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の仕方が変わるのでそれも変更すると、最終的に修正内容の形になり、無事エラーなく実行できるようになりました

参考

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?