はじめに
2025年8月にAWS Lambdaのアップデートがあり,デプロイ用のアクションがaws-actionsより提供されるようになりました!
先日投稿した記事では,このアクションを使用し,従来の方法よりも簡単にかつ高速にLambda関数をPythonのランタイムでデプロイすることができるようになったので,その方法をまとめました.
この記事では,その続編として,コードをTypeScriptで記述したLambda関数をローカルからデプロイします.
従来のAWS Lambda with TypeScript
Lambda関数をTypeScriptで記述することの需要は当然あります.静的型付け言語による開発は間違いなく魅力的です.
自分も所属しているKDDIアジャイル開発センターの記事でもTypeScriptでLambda関数を記述する方法についてまとめたものがあります.
しかし,従来のTypeScriptを用いたLambda関数での開発はそれなりにめんどくさいです(慣れれば簡単みたいですが).
TypeScriptは実行前にJavaScriptへのトランスパイルが必要であり,依存ライブラリも一緒にパッケージング(バンドル)する必要があるため,デプロイまでの手順が複雑になりがちでした.
これらの複雑な手順をIaCで定義するのはそれなりにめんどくさいです.そのため,IaCを使用せずにデプロイできるようになった今回のアップデートで,TypeScriptsを用いてのLambda関数での開発がかなり簡単になりました.しかもnode_module
を.gitingore
に含めることができるのでデプロイもとても高速です.
この記事ではその方法について簡単にまとめます.
実装
今回はhello from TypeScript!
というメッセージが入ったjsonが返ってくるシンプルなLambda関数をデプロイします.
ディレクトリ構成
TypeScriptのプロジェクトでは,ソースコードを管理するsrc
ディレクトリと,トランスパイル後のJavaScriptが出力されるdist
ディレクトリを分けるのが一般的です.
├── .github
│ └── workflows
│ └── deploy_lambda.yml
└── hello_lambda_ts
├── package.json
├── tsconfig.json
└── src
└── index.ts
src/index.ts
がLambda関数の本体です.hello_lambda_ts
ディレクトリが1つのLambda関数プロジェクトになります.
IAMユーザーを用意する
この手順は前回のPython編と全く同じです.Lambda関数をデプロイするためのアクセスキーとシークレットアクセスキー,そしてLambda関数に割り当てるIAMロールのARNを用意し,GitHubリポジトリのSecretsに登録してください.
詳細は前回の記事を参照してください.
TypeScriptプロジェクトをセットアップする
まず,hello_lambda_tsディレクトリを作成し,その中でNode.jsプロジェクトを初期化します.
mkdir hello_lambda_ts
cd hello_lambda_ts
npm init -y
次に関数の開発に必要なライブラリをインストールします.
typescript
: TypeScriptコンパイラ
esbuild
: 高速なTypeScriptのトランスパイラ兼バンドラ
@types/node
, @types/aws-lambda
: 型定義ファイル
npm install --save-dev typescript esbuild @types/node @types/aws-lambda
これらの作業で発生した以下のディレクトリ,ファイルは.gitignore
に追加してください.
# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# TypeScript
*.tsbuildinfo
dist/
build/
今回は,トランスパイルとバンドルを高速に行えるesbuild
を使用します.
デプロイする関数と設定ファイルを用意する
hello_lambda_ts
ディレクトリ内に以下のファイルを作成します.
tsconfig.json
TypeScriptのコンパイル設定を記述します.
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist"
},
"include": ["src/**/*"]
}
package.json
esbuild
を使ってビルドするためのスクリプトをscripts
に追加します.
"main"
のエントリポイントもビルド後のファイルを指すように変更しておきましょう.
{
"name": "hello_lambda_ts",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"scripts": {
"build": "esbuild src/index.ts --bundle --minify --sourcemap --platform=node --target=node20 --outfile=dist/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.138",
"@types/node": "^20.12.12",
"esbuild": "^0.25.9",
"typescript": "^5.4.5"
}
}
今回はnodeのバージョンを20.x
としているため,npm install
した時のバージョンが24などになっている場合は上記ののjsonと同じように20.x
でするか,後述するymlファイルのNODE_VERSION
を24.x
などにしてpackage.json
とpackage-lock.json
, deploy_lambda.yml
でバージョンの齟齬が起こらないようにしてください.
AIで解決できる簡単なエラーが発生するだけなので,とりあえずデプロイしてエラーが発生したらAIに噛ませるでもいいと思いますが
それ以外はnpm install
した時のままで大丈夫です.
build
スクリプトは,src/index.ts
をエントリーポイントとして,依存関係をすべてバンドルし,Node.js 20.x
環境で実行可能な単一のdist/index.js
ファイルを生成します.
src/index.ts
message: hello from TypeScript!
を返すだけのシンプルなhandlerです.
import { APIGatewayProxyHandler } from 'aws-lambda';
export const handler: APIGatewayProxyHandler = async (event, context) => {
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
message: 'hello from TypeScript!',
}),
};
};
ymlファイルを用意する
以下のymlがGitHub Actionsで動作するworkflowです.Python編との違いは,Node.jsのセットアップ,依存関係のインストール,ビルドステップです.
name: Deploy-Lambda-TypeScript
on:
push:
branches:
- "main"
pull_request:
paths:
- "hello_lambda_ts/**"
- ".github/workflows/deploy_lambda.yml"
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: "hello_lambda_ts"
env:
NODE_VERSION: 20.x
function-name: hello_lambda_ts_actions
lambda-role-arn: ${{ secrets.LAMBDA_ROLE_ARN }}
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Deploy Lambda
uses: aws-actions/aws-lambda-deploy@v1.0.1
with:
function-name: ${{ env.function-name }}
code-artifacts-dir: ./hello_lambda_ts/dist
handler: index.handler
runtime: nodejs${{ env.NODE_VERSION }}
role: ${{ env.lambda-role-arn }}
timeout: 30
Deploy Lambdaステップの解説 (TypeScript編)
Python編とほぼ同じですが,いくつかTypeScript特有の注意点があります.
code-artifacts-dir
esbuild
によって生成されたJavaScriptファイルが格納されているdist
ディレクトリを指定します.GitHub Actionsのルートからのパスで指定するため,./hello_lambda_ts/dist
としています.
handler
ファイル名.エクスポートした関数名の形式で指定します.今回はdist/index.js
ファイルの中のhandler関数なので,index.handler
となります.
runtime
nodejs20.x
のように,使用したいNode.jsのバージョンを指定します.
実装完了
これで準備は完了です.mainブランチへのpushかプルリクエスト作成時,更新時にLambda関数のビルドとデプロイが実行されます.デプロイが完了すると,マネジメントコンソールで以下のように確認でき,[Test]タブから実行テストも行えます.
めちゃくちゃ簡単にTypeScriptでLambda関数を作成し,デプロイすることができました.
付録
TypeScriptでの開発をより実用的にするための付録です.
付録1:ローカルでも実行したい
ts-node
を使うと,TypeScriptファイルを直接実行できるのでローカルでの動作確認が簡単です.
npm install --save-dev ts-node
テスト用のコードをsrc/index.ts
の末尾に追記します.
// ... handler関数のコード ...
// スクリプトが直接実行された場合にテストコードを呼び出す
if (require.main === module) {
console.log("--- Running Local Test ---");
// @ts-ignore
handler({}, {}).then(result => {
console.log(JSON.parse(result.body));
});
console.log("--- End of Local Test ---");
}
そして,package.json
にstart
スクリプトを追加します.
"scripts": {
"start": "ts-node src/index.ts",
"build": "..."
},
npm start
コマンドでローカル実行できます.
付録2:外部ライブラリを使用したい
例えばaxiosを使って外部APIを叩く場合,まずはライブラリをインストールします.
npm install axios
npm install --save-dev @types/axios
あとはコード内でimportして使用するだけです.
今回のコードも以前のPython編と同じくピカチュウの名前を図鑑ナンバーからpokeAPIで取得して返しているだけです.
import { APIGatewayProxyHandler } from 'aws-lambda';
import axios from 'axios';
// PokeAPI のレスポンス型定義
interface PokemonResponse {
name: string;
id: number;
}
export const handler: APIGatewayProxyHandler = async (event, context) => {
const response = await axios.get<PokemonResponse>('https://pokeapi.co/api/v2/pokemon/25');
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
message: response.data.name,
}),
};
};
esbuild
がビルド時にaxios
のコードもまとめてdist/index.js
にバンドルしてくれるため,ymlファイルを変更する必要はありません.esbuild
めっちゃ便利...
おわりに
今回は,新しく提供が開始されたGitHub Actions (aws-actions/aws-lambda-deploy
) を使って,TypeScriptで記述したAWS Lambda関数をデプロイする方法を紹介しました.
従来,TypeScriptでのLambda開発はトランスパイルやバンドルの設定が手間に感じられることがありましたが,esbuild
のようなモダンなツールと新しいGitHub Actionsを組み合わせることで,CI/CDパイプラインの構築が非常にシンプルかつ高速になりました.
静的型付けの恩恵を受けながら,インフラ管理のコストを抑え,コードの変更を即座に反映できるこの方法は,あらゆる規模のプロジェクトで強力な選択肢になるはずです.
最後までお読みいただき、ありがとうございました.