この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
既存のLambdaをAWS Amplify + Reactから呼び出してみました。
背景
Step Functionsなどを用いて、Lambdaを単機能で疎結合な構成で実装している場合、他のインタフェースからも呼び出して再利用したい場合があるかと思います。AWS AmplifyにはLambdaを追加定義するamplify add function
コマンドとamplify add api
コマンドで追加したAPIからLambdaを呼び出す@function
ディレクティブがありますが、今回はシンプルにReactからaws-sdk
のLambda Clientを使ってLambdaを呼び出してみました。
解法
import React, { useState } from 'react'
import { Auth } from 'aws-amplify'
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda'
import Box from '@mui/material/Box'
import TextField from '@mui/material/TextField'
import Button from '@mui/material/Button'
const initialState = {
lambdaArgs1: '',
lambdaArgs2: ''
}
const SomeLambdaInvoker = () => {
const [formState, setFormState] = useState(initialState)
const setInput = (key, value) => {
setFormState({ ...formState, [key]: value })
}
const invoke = async() => {
const credentials = await Auth.currentCredentials()
const client = new LambdaClient({
credentials: Auth.essentialCredentials(credentials),
region: process.env.REACT_APP_LAMBDA_REGION
})
const input = {
FunctionName: 'some-existing-lambda-' + process.env.REACT_APP_STAGE,
Payload: JSON.stringify(formState)
}
const command = new InvokeCommand(input)
const response = await client.send(command)
if (response) {
setFormState(initialState)
} else {
console.error(response.error)
}
}
return (
<Box
sx={{
p: 2,
bgcolor: 'background.default',
display: 'grid',
gridTemplateColumns: { md: '1fr 1fr' },
gap: 2,
}}
>
<TextField
required
id="lambda-args1"
label="Lambda関数への引数1"
type="text"
onChange={event => setInput('lambdaArgs1', event.target.value)}
value={formState.lambdaArgs1}
/>
<TextField
required
id="lambda-args2"
label="Lambda関数への引数2"
type="text"
onChange={event => setInput('lambdaArgs2', event.target.value)}
value={formState.lambdaArgs2}
/>
<Button
variant="contained"
onClick={invoke}
>
Submit
</Button>
</Box>
)
}
export default SomeLambdaInvoker
some-existing-lambda-{dev|prod}
という名前の既存のLambdaを呼び出す例になっています。
LambdaClient
コンストラクタにはAmplifyのAuthモジュールから得たクレデンシャルを指定します。Amplifyの認証を通ったユーザのみにLambdaの呼び出しを許可しています。なお、Amplifyの実行ロールにはlambda:InvokeFunction
権限が必要です。ポリシー設定は下記のように行います。Resourceで実行を許可するLambda関数のARNを厳密に絞り込むことをオススメします。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LambdaInvokeSetting",
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:some-existing-lambda-dev"
}
]
}
InvokeCommand
コンストラクタにFunctionName
で呼び出したいLambda名、Payload
にLambdaで与えたいパラメータを指定し、LambdaClient.send(command)
メソッドでLambda呼び出しを実行します。
なお、.env
ファイルには下記のような設定をしています。環境に合わせて書き換えてください。
REACT_APP_STAGE=dev
REACT_APP_LAMBDA_REGION=ap-northeast-1
Lambdaの方は次のように書かれている想定です。
def lambda_handler(event, context):
print(event['lambdaArgs1']) # lambdaArgs1にアクセス
print(event['lambdaArgs2']) # lambdaArgs2にアクセス
"""
:
いろいろな処理をする
:
"""
if __name__ == "__main__":
lambda_handler({"lambdaArgs1": "", "lambdaArgs2": ""}, {})
まとめ
aws-sdk
のLambda Clientを使って既存のLambdaを呼び出してみました。Amplifyの実行ロールの権限を絞って、かつ、AmplifyのAuthモジュールと組み合わせることでCognitoで認証したユーザーに限定して既存の特定のLambdaだけを実行させることができます。参考になれば幸いです。