![見出し画像](https://assets.st-note.com/production/uploads/images/53897647/rectangle_large_type_2_6c3d06a2586519f82e58116457f7eb05.jpg?width=1200)
今から始めるServerless Frameworkでサーバーレスデビュー【ファンクション番外編#4】
番外編ではファンクション編となります。
この編ではLambda関数の記述について説明します。
functionsディレクトリの構成は以下の通りです。
├── functions
│ ├── cognito.ts
│ └── hello.ts
│ └── user.ts
serverless.ymlのfunctionsセクションの内容は以下のようになっています。
# ------------------------------------------
# functions
# ラムダで使用する関数を設定
# ------------------------------------------
functions:
# 初期ファンクション
hello:
handler: functions/hello.handler
memorySize: 128
timeout: 10
events:
- http:
path: /hello
method: get
integration: lambda
cors: true
authorizer:
name: ApiGatewayAuthorizer
type: COGNITO_USER_POOLS
authorizerId: !Ref ApiGatewayAuthorizer
# ユーザー作成認証する処理
customMessages:
handler: functions/cognito.handler
memorySize: 128
timeout: 10
events:
- cognitoUserPool:
pool: ${self:service}-user-pool-${opt:stage, self:provider.stage}
trigger: CustomMessage
existing: true
# ユーザー作成時にDBに情報を格納する処理
postConfirmation:
handler: functions/user.handler
memorySize: 128
timeout: 10
events:
- cognitoUserPool:
pool: ${self:service}-user-pool-${opt:stage, self:provider.stage}
trigger: PostConfirmation
existing: true
eventsには通常のGETやPOSTなどのリクエストを設定することができます。
これにより、API GatewayのAPIとして機能させることができます。
また、eventsにCognitoを指定することで、Cognitoのフローの中でトリガーを起点に処理を行うことができます。
Cognitoを使用する場合、既存のユーザープールにアタッチする場合は、existingをtrueに設定しないと新たにCognitoユーザープールが作成されてしまうので注意が必要です。
以下のようにすることで、Lambda Functionであるcognito.tsを以下のように設定すれば、Cognitoのトリガーで処理を挟むことができるfunctionsとなります。
// fucntions/cognito.ts
import { CognitoUserPoolTriggerEvent, Context, Callback } from 'aws-lambda';
// ------------------------------------------
// ユーザー作成認証する処理
// ------------------------------------------
export const handler = (event: CognitoUserPoolTriggerEvent, context: Context, callback: Callback) => {
/**
* 新規登録のとき
*/
if (event.triggerSource === 'CustomMessage_SignUp') {
event.response.smsMessage = `あなたのサービス確認コードは${event.request.codeParameter}です`
event.response.emailSubject = '新規登録の確認コード'
event.response.emailMessage = `下記URLからユーザー登録を完了してください。\<br\> URL: http://localhost:3000/signup/confirm?email=${encodeURIComponent(event.request.userAttributes.email)}&username=${event.userName}&code=${event.request.codeParameter} \<br\> Code: ${event.request.codeParameter}`
/**
* 認証コード再送信
*/
} else if(event.triggerSource === 'CustomMessage_ResendCode'){
event.response.smsMessage = `あなたのサービス確認コードは${event.request.codeParameter}です`
event.response.emailSubject = '【再送信】新規登録の確認コード'
event.response.emailMessage = `下記URLからユーザー登録を完了してください。\<br\> URL: http://localhost:3000/signup/confirm?email=${encodeURIComponent(event.request.userAttributes.email)}&username=${event.userName}&code=${event.request.codeParameter} \<br\> Code: ${event.request.codeParameter}`
/**
* パスワードを忘れたとき
*/
} else if(event.triggerSource === 'CustomMessage_ForgotPassword') {
event.response.smsMessage = `あなたのサービス確認コードは${event.request.codeParameter}です`
event.response.emailSubject = 'パスワードリセットの確認コード'
event.response.emailMessage = `下記URLからパスワード再登録を行ってください。\<br\> URL: http://localhost:3000/signup?email=${encodeURIComponent(event.request.userAttributes.email)}&username=${event.userName}&code=${event.request.codeParameter} \<br\> Code: ${event.request.codeParameter}`
}
callback(null, event)
}
Lambdaのfunctionsでは上記のように、各関数に対して個別の設定を行うことができます。
eventsを使用してAPI Gatewayとの結びつきやCognitoとのトリガーを設定することで、様々な動作や挙動を実現することができます。
①Cognitoのtriggerでの活用。
②REST APIとして活用。
③LambdaからLambdaの処理を行うInvokeとして活用。
④AppSyncのデータソースとしてLambdaを活用。
上記のように、functionsの設定によって様々な活用が可能となっており、サーバーレスを最大限活用するためには必須の項目です。
関数ごとに個別の設定を行うことで、API Gatewayとの結びつきやCognitoのトリガーを活用した動作を実現することができます。
1.API GateWayとして使用する
例えば、"hello"という関数のようにREST APIとしてLambdaを機能させることも可能です。
今回のREST APIでは、CognitoのAuthorizerを使用しています。Cognitoの認証が完了した後、JWT(JSON Web Token)をリクエストのヘッダーに含めないと、APIを叩くことができません。
この仕組みにより、APIのセキュリティを確保しています。
// fucntions/hello.ts
import { Context, APIGatewayProxyResult, Callback } from 'aws-lambda';
export const handler = async (event: APIGatewayProxyResult, context: Context, callback: Callback) => {
const message = 'Hello World.'
const response = {
statusCode: 200,
'headers': {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({
context: context,
event: event,
message: message
})
}
callback(null, response);
};
フロントエンドでは、エンドポイントにリクエストを送信し、返ってきたレスポンスJSONをパースして処理します。
JSON.parse(res.data.body)
レスポンスのbody内の値にアクセスすることができるようになります。
serverless.ymlを使用することで、LambdaをREST APIとして簡単に利用することができます。
2.LambdaからDynamoDBをさわってみる
// functions/user.ts
import * as AWS from 'aws-sdk';
import { CognitoUserPoolTriggerEvent, Context, Callback } from 'aws-lambda';
// ------------------------------------------
// User作成完了時ユーザー情報をUserテーブルに書き込む
// ------------------------------------------
export const handler = (event: CognitoUserPoolTriggerEvent, callback: Callback) => {
// DynamoDBを初期化
const dynamoDB = new AWS.DynamoDB.DocumentClient({
region: "ap-northeast-1"
});
// DBに保存する値
const params = {
TableName: 'my-serverless-backend-dev-User',
Item: {
'userId': event.userName,
"username": event.userName,
"email": event.request.userAttributes.email
}
}
// DBに保存
dynamoDB.put(params).promise().then(() => {
callback(null, event)
}).catch((error) => {
callback(new Error(`${error} Couldn\'t create the todo item.`), event)
})
}
ユーザーの新規登録後、ユーザー確認が完了すると、ユーザー情報がDynamoDBのUserテーブルに書き込まれます。
この場合、Cognitoで認証を管理しているため、アドレスなどの情報を持つ必要がないため、この方法は適切ではありません。
ただし、LambdaからDynamoDBにデータを書き込む方法として一例として紹介しています。
注意点として、DynamoDBにデータを書き込んだ後は、callback(null, event)を呼び出しましょう。
以前はcontext.done(event)と書かれている記事もありましたが、現在は非推奨とされており、エラーが発生することがあるため、今後はcallbackを使用する方が良いでしょう。
● 今から始めるServerless Frameworkでサーバーレスデビュー【バックエンド編#1】
https://note.com/ryoppei/n/n9163712b68ad
● 今から始めるServerless Frameworkでサーバーレスデビュー【フロントエンド編#2】
https://note.com/ryoppei/n/n0858cfca7784
● 今から始めるServerless Frameworkでサーバーレスデビュー【プラグイン番外編#3】
https://note.com/ryoppei/n/ne110ac6a440f
● 今から始めるServerless Frameworkでサーバーレスデビュー【ファンクション番外編#4】
https://note.com/ryoppei/n/n71809e2520e0
● 今から始めるServerless Frameworkでサーバーレスデビュー【マッピングテンプレート番外編#5】
https://note.com/ryoppei/n/n20b4afd705e5