AWS SAMを使って最もシンプルにLambda × APIGatewayのWebAPIを構築する

# 概要

今回は前回紹介したAWS LambdaのAWS サーバーレスアプリケーションモデル (Serverless Application Model)、AWS SAMの続編になります。

【前回の記事】
[AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～](https://www.studycloudtech.com/aws/lambda-sam-start-cloud9/ "AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～")

SAMの便利さは前回の記事でなんとなくわかったと思うので今回からはより実践編です。
実際にSAMを使ってAWSのサービスを連携させてみようという内容です。

第一回は、Lambda × APIGateway 編にしました。
この投稿を最後まで実行すると以下の図のようなAWSサービスで構築したWebAPI環境が、なんと**2ファイル30ライン**ほどで完成します。
理解しやすいように**最もシンプルな記載例**としてファイルサンプルを作成したので実際に作ったファイルを見るとこんなに簡単なのかを思えると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/31de61b0-e2f5-208a-1d21-256b1547f1c5.png)

実はSAMリポジトリという以下のURLにサンプルアプリケーションはたくさんあるのですが、なかなか初見では理解しにくいものが多いので今回は最もシンプルな記載例に心掛けています。

https://serverlessrepo.aws.amazon.com/applications

## 想定読者
* Lambda × APIGateway でAPIサービスを作りたい人
* LambdaでSAMを使ってみたい人
* Lambdaの知識をレベルアップしたい人

## 作業時間

* 15分（Cloud9などSAMの環境作成除く(^^;)）

## 参考書籍

[AWS Lambda実践ガイド 第2版](https://amzn.to/3E5O6xm "AWS Lambda実践ガイド 第2版")
<a href="https://www.amazon.co.jp/AWS-Lambda%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E7%AC%AC2%E7%89%88-impress-gear/dp/4295013307?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=RTIKKZ2CFWRN&keywords=lambda&qid=1649573956&sprefix=lambda%2Caps%2C259&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEyRlJEWjJYMjVSTlkyJmVuY3J5cHRlZElkPUEwMDQ2MDAxMkxOTDlZODNUMDJKVSZlbmNyeXB0ZWRBZElkPUFZUFVHWkVYQkwxRUkmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl&linkCode=li1&tag=aws_lambda_002-22&linkId=642f50ab03838b3aabea490e9486a91c&language=ja_JP&ref_=as_li_ss_il" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=4295013307&Format=_SL110_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=aws_lambda_002-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=aws_lambda_002-22&language=ja_JP&l=li1&o=9&a=4295013307" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

[【Kindle版】AWS Lambda実践ガイド 第2版](https://amzn.to/37vUsd1 "【Kindle版】AWS Lambda実践ガイド 第2版")
<a href="https://www.amazon.co.jp/AWS-Lambda%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E7%AC%AC2%E7%89%88-impress-gear%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-ebook/dp/B09TVG5H17?_encoding=UTF8&qid=1649573956&sr=8-1-spons&linkCode=li1&tag=aws_lambda_002-22&linkId=51d23857df9fcbf5549fcd41fdf628da&language=ja_JP&ref_=as_li_ss_il" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B09TVG5H17&Format=_SL110_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=aws_lambda_002-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=aws_lambda_002-22&language=ja_JP&l=li1&o=9&a=B09TVG5H17" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

ほぼほぼこの本を参考にさせて頂きました。
Lambdaに特化した本はあまりないので現時点で唯一の専門書と思います。
Lambdaを勉強するなら誰でもまずこの本から勉強するのではないかと思える代表的な本になっていると思います。

Lambdaの良書が増えてきたので、おすすめ本5冊を以下で紹介しています。Lambdaについて本格的に勉強したい方はぜひ読んでみてください。

[AWS Lambdaおすすめ書籍5冊の紹介](https://www.studycloudtech.com/aws/aws-lambda-books/ "AWS Lambdaおすすめ書籍5冊の紹介")

## 目次

* SAM環境（Cloud9環境）準備
* Lambda × APIGateway テンプレートファイル作成
* Lambda ソースファイル作成
* ビルド
* デプロイ

## SAM環境（Cloud9環境）準備

以前の以下の記事を参考にCloud9の環境を作ってください。
**ディスク拡張を忘れず(^^;)**
[AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～](https://www.studycloudtech.com/aws/lambda-sam-start-cloud9/ "AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～")

## Lambda × APIGateway テンプレートファイル作成

Cloud9環境が作成されたら実際にAWSサービス構築用のファイルを作成していきます。
作成するファイルは2つ(**template.yaml**/**app.py**)。最終的には以下のフォルダ構成になるように2ファイル作成してください。

```
sam-api-sample
│  template.yaml
└─hello_world
　    app.py
```

ルートフォルダは**sam-api-sample**という名前にしています。こちらのフォルダ名は任意なので必要であれば変えてください。他のフォルダ名／ファイル名を変更する場合、それに伴った設定を変える必要があるので少し慣れてきてからにした方が良いと思います(^^;)



それではまず**template.yaml**で**Lambda × APIGateway テンプレート**ファイル作成します。
ファイル内容は以下の通り。

```template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  Sample SAM Template for sam-api-sample

Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get

Outputs:
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn
```

記載内容を極力シンプルにしたので定義内容もなんとなくわかると思いますが、
抜粋で記載内容を説明すると、、、
* Timeout: 3（Lambdaの処理タイムアウト3秒）
* CodeUri: hello_world/（Lambdaの実ファイルはhello_worldフォルダにあり）
* Handler: app.lambda_handler（app.pyファイルのlambda_handler関数が呼ばれる）
* Path: /hello（アクセスするときのAPIGatewayのパスは/hello）
* Method: get（HTTP GETメソッドでアクセスする）
ことを定義しています。

これらはもちろんAWSコンソールから設定できるのですが、頻繫に？画面UIが改善されるAWSコンソールをその都度迷いながら設定するよりこの**ファイル1つで構築できるのSAMの非常に便利なところ**と思っています。

加えてファイル内容について補足すると、**Outputs**以降は実際に作成されたLambdaやAPIのURLを出力するようにしていますが、実際にはなくても構いません。そのため、実際に構築に必要な設定は、**Outputs**の上までなので、なんとたったの**24ライン**でLambda × APIGateway環境が出来上がります！簡単ですね。

## Lambda ソースファイル作成

では、次のファイル**app.py**に移ります。
**app.py** は、実際にAPIアクセスされたときに実行されるLambda関数になります。
今回は単純なサンプルということで処理の中身はなく、hello worldを返すだけの処理にしています。
たったの**5ライン**！
上で紹介したフォルダ構成で**hello_world**フォルダの下に配置しましょう。

```app.py
def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "body":"message: hello world",
    }
```

最終的にCloud9環境で見えるフォルダ構成が以下のようになっていれば問題ありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/6171d73d-d507-489f-3918-ef9f32bbeac9.png)



## ビルド

準備はここまでです。たった**2フォルダ／2ファイル**で非常に簡単ですね。

それではビルドします。
ルートフォルダ**sam-api-sample**に移動して、
　**sam build --use-container**
実行しましょう。

このあたりのコマンドは前回の記事に記載しているので必要であれば以下の前回の記事を参照してください。
【前回の記事】
[AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～](https://www.studycloudtech.com/aws/lambda-sam-start-cloud9/ "AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～")

以下に実際のコマンド実行結果を載せています。
```sh
$ cd sam-api-sample
$ sam build --use-container
Starting Build inside a container
Your template contains a resource with logical ID "ServerlessRestApi", which is a reserved logical ID in AWS SAM. It could result in unexpected behaviors and is not recommended.
Building codeuri: /home/ec2-user/environment/Cloud9_SAM/sam-api-sample/hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: ['HelloWorldFunction']

Fetching public.ecr.aws/sam/build-python3.9:latest-x86_64 Docker container image............................................................................................................................................................................................................................................................................................................
Mounting /home/ec2-user/environment/Cloud9_SAM/sam-api-sample/hello_world as /tmp/samcli/source:ro,delegated inside runtime container

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
[*] Deploy: sam deploy --guided
        
requirements.txt file not found. Continuing the build without dependencies.
Running PythonPipBuilder:CopySource
$
```

ディスク容量が問題なければ無事にビルドできると思います(^^;)
くどいようですが、ディスク容量でエラー（**RuntimeError: Container does not exist. Cannot get logs for this container**）が出たら前回の記事を参照してください。

【前回の記事】
[AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～](https://www.studycloudtech.com/aws/lambda-sam-start-cloud9/ "AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～")

## デプロイ

続いてデプロイです。
　**sam deploy --guided --capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND**
実行しましょう。

```sh
$ sam deploy --guided --capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: sam-api-sample
        AWS Region [ap-northeast-1]: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: y
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y 
        Save arguments to configuration file [Y/n]: y
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

        Looking for resources needed for deployment:
         Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-bncdmvrv3w3n
         A different default S3 bucket can be set in samconfig.toml

        Saved arguments to config file
        Running 'sam deploy' for future deployments will use the parameters saved above.
        The above parameters can be changed by modifying samconfig.toml
        Learn more about samconfig.toml syntax at 
        https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

Uploading to sam-api-sample/1948bce135b64124xd47a657530b44f58  178 / 178  (100.00%)

        Deploying with following values
        ===============================
        Stack name                   : sam-api-sample
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : True
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-bncxdmvrv3w3n
        Capabilities                 : ["CAPABILITY_IAM", "CAPABILITY_AUTO_EXPAND"]
        Parameter overrides          : {}
        Signing Profiles             : {}

Initiating deployment
=====================
Uploading to sam-api-sample/e7b773fc9b0c22cdxc3f859f9f36ed735.template  1182 / 1182  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                               LogicalResourceId                       ResourceType                            Replacement                           
-------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                   HelloWorldFunctionHelloWorldPermissio   AWS::Lambda::Permission                 N/A                                   
                                        nProd                                                                                                                 
+ Add                                   HelloWorldFunctionRole                  AWS::IAM::Role                          N/A                                   
+ Add                                   HelloWorldFunction                      AWS::Lambda::Function                   N/A                                   
+ Add                                   ServerlessRestApiDeployment47fc2d5f9d   AWS::ApiGateway::Deployment             N/A                                   
+ Add                                   ServerlessRestApiProdStage              AWS::ApiGateway::Stage                  N/A                                   
+ Add                                   ServerlessRestApi                       AWS::ApiGateway::RestApi                N/A                                   
-------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:changeSet/samcli-deployx1657935682/b46c7900-abb9x-4ec1-a2df-1fd2159251ea


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2022-07-16 01:41:37 - Waiting for stack create/update to complete

CloudFormation events from stack operations
-------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                          ResourceType                            LogicalResourceId                       ResourceStatusReason                  
-------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                      AWS::IAM::Role                          HelloWorldFunctionRole                  -                                     
CREATE_IN_PROGRESS                      AWS::IAM::Role                          HelloWorldFunctionRole                  Resource creation Initiated           
CREATE_COMPLETE                         AWS::IAM::Role                          HelloWorldFunctionRole                  -                                     
CREATE_IN_PROGRESS                      AWS::Lambda::Function                   HelloWorldFunction                      -                                     
CREATE_IN_PROGRESS                      AWS::Lambda::Function                   HelloWorldFunction                      Resource creation Initiated           
CREATE_COMPLETE                         AWS::Lambda::Function                   HelloWorldFunction                      -                                     
CREATE_IN_PROGRESS                      AWS::ApiGateway::RestApi                ServerlessRestApi                       -                                     
CREATE_IN_PROGRESS                      AWS::ApiGateway::RestApi                ServerlessRestApi                       Resource creation Initiated           
CREATE_COMPLETE                         AWS::ApiGateway::RestApi                ServerlessRestApi                       -                                     
CREATE_IN_PROGRESS                      AWS::ApiGateway::Deployment             ServerlessRestApiDeployment47fc2d5f9d   -                                     
CREATE_IN_PROGRESS                      AWS::Lambda::Permission                 HelloWorldFunctionHelloWorldPermissio   -                                     
                                                                                nProd                                                                         
CREATE_IN_PROGRESS                      AWS::Lambda::Permission                 HelloWorldFunctionHelloWorldPermissio   Resource creation Initiated           
                                                                                nProd                                                                         
CREATE_IN_PROGRESS                      AWS::ApiGateway::Deployment             ServerlessRestApiDeployment47fc2d5f9d   Resource creation Initiated           
CREATE_COMPLETE                         AWS::ApiGateway::Deployment             ServerlessRestApiDeployment47fc2d5f9d   -                                     
CREATE_IN_PROGRESS                      AWS::ApiGateway::Stage                  ServerlessRestApiProdStage              -                                     
CREATE_IN_PROGRESS                      AWS::ApiGateway::Stage                  ServerlessRestApiProdStage              Resource creation Initiated           
CREATE_COMPLETE                         AWS::ApiGateway::Stage                  ServerlessRestApiProdStage              -                                     
CREATE_COMPLETE                         AWS::Lambda::Permission                 HelloWorldFunctionHelloWorldPermissio   -                                     
                                                                                nProd                                                                         
CREATE_COMPLETE                         AWS::CloudFormation::Stack              sam-api-sample                          -                                     
-------------------------------------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                      
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                                
Description         Implicit IAM Role created for Hello World function                                                                                       
Value               arn:aws:iam::XXXXXXXXXXXX:role/sam-api-sample-HelloWorldFunctionRole-1XVQC0GREGPQ7X                                                       

Key                 HelloWorldApi                                                                                                                            
Description         API Gateway endpoint URL for Prod stage for Hello World function                                                                         
Value               https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/                                                                  

Key                 HelloWorldFunction                                                                                                                       
Description         Hello World Lambda Function ARN                                                                                                          
Value               arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:sam-api-sample-HelloWorldFunction-1JRYV5PA3BbB                                       
--------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - sam-api-sample in ap-northeast-1

$
```

対話型のやり取りになるので以下のように求められた内容に対し回答を入力します。
**[]** 内に記載されたデフォルトで良ければそのままEnterで大丈夫です。

* Stack Name [sam-app]: **sam-api-sample**
* AWS Region [ap-northeast-1]: 
* Confirm changes before deploy [y/N]: **y**
* Allow SAM CLI IAM role creation [Y/n]: **y**
* Disable rollback [y/N]: **y**
* HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: **y**
* Save arguments to configuration file [Y/n]: **y**
* SAM configuration file [samconfig.toml]: 
* SAM configuration environment [default]: 
* Deploy this changeset? [y/N]: **y**

このやり取りは、**SAM configuration file [samconfig.toml]** に保存されるので、
次回は**sam deploy**というオプション無しの簡単なコマンド実行で大丈夫です。

それではデプロイが問題なく完了したら構築されたAPIGatewayのURLにブラウザでアクセスして動作確認してみます。
アクセス先はデプロイコマンドの最後に出力されている以下のアクセスURLになります。（template.yamlでOutputsに指定した内容になります）

```
Key                 HelloWorldApi
Description         API Gateway endpoint URL for Prod stage for Hello World function
Value               https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
```

問題なく構築出来ていれば、以下の内容がブラウザに表示されるはずです。（app.pyの処理結果です）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188544/3f65f145-6c5a-521d-dcea-0a6b0568d8f3.png)

以上！非常に簡単だったのではないでしょうか。
これでAWSコンソールの画面UIが変わるたびに設定内容に迷う必要がなくなりました(^^)

## まとめ
お疲れ様でした！

今回はLambdaでsamを使って**Lambda × APIGateway**の環境を構築してみました。環境設定を **template.yml** に実処理を**app.py**に記載できて、後はコマンド実行で完了するので、再現性が高く、ファイル群はGitなどで履歴管理できるので非常に便利になると思います。
samを使ってプログラム集中出来るサーバーレスLambdaがもっと便利になって、開発者はより業務ロジックに集中出来る世の中になれば良いなと思います(^^)

本投稿が少しでも皆さんの良いサーバーレスライフの助けになればと思います(_ _)

## 資格取得に向けてAWSサービスを実際に利用してみるシリーズの投稿一覧

[とりあえず30分でAWS利用料金の高額請求に備える～予算アラート設定・MFA・料金確認～](https://qiita.com/fkooo/items/67c53c997508e25605ea "とりあえず30分でAWS利用料金の高額請求に備える～予算アラート設定・MFA・料金確認～")
[AWS ECSでDocker環境を試してみる](https://qiita.com/fkooo/items/d7d98e16e91921508450 "AWS ECSでDocker環境を試してみる")
[Amazon Cognitoを使ってシンプルなログイン画面を作ってみる](https://qiita.com/fkooo/items/660cab0090a80861155b "Amazon Cognitoを使ってシンプルなログイン画面を作ってみる")
[AWS NATゲートウェイを使ってプライベートサブネットからインターネットにアクセスする](https://qiita.com/fkooo/items/a474db0f3c2e72448d36 "AWS NATゲートウェイを使ってプライベートサブネットからインターネットにアクセスする")
[API GatewayをPrivateで作成してみる](https://qiita.com/fkooo/items/577831abd9803eb91b16 "API GatewayをPrivateで作成してみる")
[AWSのAI(Rekognition/Polly/Transcribe/Comprehend/Translate/Textract)サービスを試してみる](https://qiita.com/fkooo/items/10f75bafd08c60fc0a66 "AWSのAI(Rekognition/Polly/Transcribe/Comprehend/Translate/Textract)サービスを試してみる")
[AWS Lambda 同時実行数、エイリアス、環境変数とか実際の現場で使える機能を勉強してみる](https://qiita.com/fkooo/items/1b24e01252e145a378db "AWS Lambda 同時実行数、エイリアス、環境変数とか実際の現場で使える機能を勉強してみる")
[AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～](https://www.studycloudtech.com/aws/lambda-sam-start-cloud9/ "AWS Lambda SAMとは？～Cloud9でSAM Sampleを使ってPythonのLambdaプログラムを簡単にデプロイする～")
[AWS SAMを使って最もシンプルにLambda × APIGatewayのWebAPIを構築する](https://qiita.com/fkooo/items/e08cdea0f73f60dabd3d "AWS SAMを使って最もシンプルにLambda × APIGatewayのWebAPIを構築する")（本記事）
[AWS SAMを使って最もシンプルにLambda × S3 のS3イベント駆動プログラムを構築する](https://qiita.com/fkooo/items/fa1d03c1d9e532956e2d "AWS SAMを使って最もシンプルにLambda × S3 のS3イベント駆動プログラムを構築する")