AWS Amplify + API Gateway + Lambda + Pythonで正常なレスポンスを返す


AWS AmplifyでLambda+API Gatewayを構成しているときに、テスト実行をしてみても正常なレスポンスが得られずに少し困ることがありあました。なので、AmplifyでのAPIの追加の仕方と合わせて、備忘録と学習を兼ねて書きます。

結論

結論からいうと、API GatewayからLambda関数を呼び出すときは、以下のようなレスポンスを返すようにする必要があるようです。

プロキシ統合のための Lambda 関数の出力形式

return {
    "isBase64Encoded": true|false,
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... },
    "body": "..."
}

headersnultiValueHeadersは特別必要ではなく、最低限statusCodebodyを返してあげればいいようです。

手順

環境

  • WIndows10 バージョン20H2
  • WSL2(Ubuntu-20.04)
  • amplify CLI 4.41.0

AmplifyでLambda関数を追加する

Amplfyでプロジェクトが作成されているところから始めます。

Lambda関数を追加します。

$ amplify add function 
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: myfunc
? Choose the runtime that you want to use: Python
Only one template found - using Hello World by default.

Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration

? Do you want to configure advanced settings? No
? Do you want to edit the local lambda function now? Yes

Do you want to edit the local lambda function now?をYesで応えると、テキストエディタが開き、以下のような初期コードが表示されます。

def handler(event, context):
  print('received event:')
  print(event)
  return {
    'message': 'Hello from your new Amplify Python lambda!'
  }

通常、Lambdaをpythonで書くと、ハンドラ名がlambda_handlerとなっていますが、Amplifyで作る場合は、handlerだけのようです。Lambdaで指定されているハンドラ名も合わせて変更されているので、特に修正する必要はありません。

正常なレスポンスとなるように変更

このままだと、API Gatewayが期待するレスポンスになっていないので、コードを以下のように修正します。

def handler(event, context):
  print('received event:')
  print(event)
  return {
      'isBase64Encoded': False,
      'statusCode': 200,
      'headers': {},
      'body': '{"message": "Hello from your new Amplify Python lambda!"}'
   }

ターミナルでEnterキーを入力すると、AmplifyプロジェクトにLambda関数が追加されます。

? Press enter to continue 
Successfully added resource myfunc locally.

Next steps:
Check out sample function code generated in <project-dir>/amplify/backend/function/myfunc/src
"amplify function build" builds all of your functions currently in the project
"amplify mock function <functionName>" runs your function locally
"amplify push" builds all of your local backend resources and provisions them in the cloud
"amplify publish" builds all of your local backend and front-end resources (if you added hosting category) and provisions them in the cloud

APIの追加

AmplifyプロジェクトにAPIを追加します。

$ amplify add api
? Please select from one of the below mentioned services: REST
? Provide a friendly name for your resource to be used as a label for this category in the project: myapi
? Provide a path (e.g., /book/{isbn}): /items
? Choose a Lambda source Use a Lambda function already added in the current Amplify project
? Choose the Lambda function to invoke by this path myfunc
? Restrict API access No
? Do you want to add another path? No
Successfully added resource myapi locally

Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

Amplifyプロジェクトの展開

このままではローカルに追加されただけなので、AmplifyプロジェクトをAWSアカウント上に展開します。

プロジェクトをAWS上に展開するには、amplify pushというコマンドを使います。
このコマンドを実行すると、以下のようにクラウド上にリソースがプロビジョニングされます。

APIのテスト実行

デフォルトではANYとしてメソッドが登録されているので、ANYを選びます。

クライアントのテストを選ぶと、メソッドやクエリ文字列を入力できる画面が表示されます。
今回はGETでテストを実行します。


期待通りのレスポンスが返ってきました。

これが、ステータスコード等が不足した正しくない形式でLambda関数のレスポンスを返すと、以下のようになります。

まとめ

Lambda + API Gatewayを使うときは、レスポンスを正しい形式にする必要があります。

また、Amplifyは簡単にAPIを実装することができて、とても楽しいです。