はじめに
参考
ハマりポイント
- Lambda関数からRDS Proxyに接続するには、LambdaをVPC内に設置する必要がある
 
- Lambda関数のサブネット、セキュリティグループをRDS Proxyと合わせる必要がある
 
- VPC内のLambda関数からSecrets Managerに接続するにはVPCエンドポイントかインターネットアクセスが必要になる
 
- PrismaとProstgreSQLのテーブル名やENUMタイプ名は大文字・小文字や複数形まで名前をあわせる必要がある
 
- Lambda関数のpermissionを設定する実行ロールには、EC2, CloudWatch, SecretsManagerの権限を付与し、Trust relationshipでは、LambdaとRDSサービスのassumeRoleの設定をする
 
- Lambdaのタイムアウトとメモリがデフォルトでは3秒と128MBと小さいので、適切に増やす
 
- PostgreSQLでは、datasouce urlでschemaまで指定する
 
- PostgreSQLのTimestampカラムには、JavaScriptのDateをISO 8601形式に変換してから設定する
 
チュートリアル
アプリ作成
npm init
npm install -D @types/aws-lambda esbuild
 
index.ts作成
import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
  console.log(`Event: ${JSON.stringify(event, null, 2)}`);
  console.log(`Context: ${JSON.stringify(context, null, 2)}`);
  return {
      statusCode: 200,
      body: JSON.stringify({
          message: 'hello world',
      }),
   };
};
 
package.jsonの編集
{
  "name": "lambda-api",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prebuild": "rm -rf dist && mkdir -p dist/node_modules",
    "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js",
    "postbuild": "cp -r node_modules/.prisma dist/node_modules/.prisma && cd dist && zip -r index.zip *"
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@types/aws-lambda": "^8.10.143",
    "esbuild": "^0.23.0"
  }
}
 
ビルド
実行ロールの作成

Lambda関数の作成
aws lambda create-function \
--function-name hello-world \
--runtime "nodejs20.x" \
--role 実行ロールのARN \
--zip-file "fileb://dist/index.zip" \
--handler index.handler
 
開発
prismaコマンドのインストール
パッケージインストール
npm install @prisma/client
npm install aws-sdk
 
schema.prisma
generator client {
  provider = "prisma-client-js"
  binaryTargets = ["native", "rhel-openssl-3.0.x"]
}
datasource db {
  provider = "postgresql"
  url      = env("DATASOURCE_URL")
}
enum meeting_type {
  google
  zoom
}
enum meeting_state {
  init
  done
  canceled
}
model meetings {
  id  Int  @id @default(autoincrement())
  order_id  Int
  meeting_type  meeting_type
  created_at  DateTime
  updated_at  DateTime
  state  meeting_state
  schedule  DateTime
  link  String?
}
 
index.ts
import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
import { PrismaClient, meeting_state, meeting_type } from '@prisma/client'
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
    const secretName = process.env.SECRET_NAME_DB_CRED;
    const secret = await secretsManager.getSecretValue({ SecretId: secretName as string }).promise();
    const dbCredentials = JSON.parse(secret.SecretString ?? '{}');
    const databaseUrl = `postgresql://${dbCredentials.username}:${dbCredentials.password}@${process.env.DATASOURCE_URL}:5432/${process.env.DB_NAME}?schema=orders`;
  
    console.log(databaseUrl);
    const prisma = new PrismaClient({
      datasources: {
        db: {
          url: databaseUrl,
        },
      },
    });  
    // console.log(prisma)
    const date = new Date();
    const isoString = date.toISOString();    
    
    const user = await prisma.meetings.create({
        data: {
          order_id: 1,
          meeting_type: meeting_type.google,
          state: meeting_state.init,
          schedule: isoString,
          link: 'aaa',
          created_at: isoString,
          updated_at: isoString
        },
      })
  return {
      statusCode: 200,
      body: JSON.stringify({
          user: user
      }),
   };
};
 
ビルド&デプロイ
package.json
  "scripts": {
    "prebuild": "rm -rf dist && mkdir dist && mkdir dist/node_modules",
    "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js",
    "postbuild": "cp -r node_modules/.prisma dist/node_modules/.prisma && cd dist && zip -r index.zip *"
  },
 
node_modules/.prisma/client, node_modules/@prisma/clientコード生成
ビルド
Lambdaコードの更新
aws lambda update-function-code \
--function-name hello-world \
--zip-file "fileb://dist/index.zip"
 
Lambdaの環境変数
- DATASOURCE_URL
 
- DB_NAME
 
- SECRET_NAME_DB_CRED
 
Lambdaの実行ロール
- Permission Policy
- EC2
 
- CloudWatch
 
- SecretsManager
 
 
- Trust relationship
- LambdaサービスのassumeRole
 
- RDSサービスのassumeRole