👋

【AWS SAM ハンズオン】API Gateway+Lambda+DynamoDBを作成。

2022/11/07に公開

記事について

簡単なものを作成してみました。

ハンズオンなどと偉そうな名前をつけておりますが、
私もSAMを触り始めて数日というレベル感です。

「気になっていたけど触ってなかったんだよね」という方に、空いた時間に軽い気持ちで触っていただければと思い公開してみたものです。

手元の環境で確認していますが、上手くいかないという事があった場合
https://twitter.com/yktAWS
までメッセージいただけたら幸いです。

事前準備(お済みでない方は)

ご自身の環境に合わせて以下ご準備ください。

AWS SAM の開始方法

AWS SAM CLI のインストール

AWS 認証情報のセットアップ

ハンズオン内容

簡単すぎる絵で恐縮ですが以下出来上がるリソースです。

ターミナルとブラウザのみご準備ください。

手順

1.親フォルダ作成 & 中に移動

ターミナル
$ mkdir apigw_lambda_dynamodb_sample && cd apigw_lambda_dynamodb_sample

2.srcフォルダ作成 & 中にapp.pyを作成

ターミナル
$ mkdir src && vi src/app.py

3.中身を貼付して保存。(i→貼付→esc→:wq→Enter)

app.py
import json
import boto3
dynamodb_client = boto3.client('dynamodb')

def lambda_handler(event, context):
    dynamodb_client.put_item(TableName='SampleTable', Item={'id': {'S': '1'}, 'value': {'S': 'Value1'}})
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "Data insertion succeeded!!!!!!!!!",
        }),
    }

4.念の為 app.py確認

ターミナル
$ cat src/app.py
# 実行結果
import json
import boto3
dynamodb_client = boto3.client('dynamodb')

def lambda_handler(event, context):
    dynamodb_client.put_item(TableName='SampleTable', Item={'id': {'S': '1'}, 'value': {'S': 'Value1'}})
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "Data insertion succeeded!!!!!!!!!",
        }),
    }

5.template.yaml作成

ターミナル
$ vi template.yaml

6.中身を貼付して保存。(i→貼付→esc→:wq→Enter)

templaye.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Apigw + Lambda + DynamoDB
Globals:
  Function:
    Timeout: 3

Resources:
  MyFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: src/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Policies:
        DynamoDBCrudPolicy:
          TableName: !Ref MyDynamoDBTable
      Events:
        ApiEvent:
          Type: Api 
          Properties:
            Path: /src
            Method: get
  MyDynamoDBTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: SampleTable

Outputs:
  Api:
    Description: "API Gateway endpoint URL"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/src/"

7.念の為 template.yaml確認

ターミナル
$ cat template.yaml
# 実行結果
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Apigw + Lambda + DynamoDB
Globals:
  Function:
    Timeout: 3

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src_world/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Policies:
        DynamoDBCrudPolicy:
          TableName: !Ref MyDynamoDBTable
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /src
            Method: get
  MyDynamoDBTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: SampleTable

Outputs:
  Api:
    Description: "API Gateway endpoint URL"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"

8.この時点でのフォルダの中身を把握

フォルダ内
 apigw_lambda_dynamodb_sample/
   ├── src/
   │   └── app.py
   └── template.yaml

9.ビルド

ターミナル
$ sam build
# 実行結果
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: /Users/[Your Directory]/apigw_lambda_dynamodb_sample/src runtime: python3.9 metadata: {} architecture: x86_64 functions: MyFunction
requirements.txt file not found. Continuing the build without dependencies.
Running PythonPipBuilder:CopySource

Build Succeeded

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

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
[*] Deploy: sam deploy --guided

10.この時点でのフォルダの中身を把握

フォルダ内
 apigw_lambda_dynamodb_sample/
   ├── .aws-sam/ [New!!]
   │   ├── build.toml
   │   └── build/
   │       ├── template.yaml
   │       └── MyFunction/
   │           └── app.py
   ├── src/
   │   └── app.py
   └── template.yaml

11.念の為、build.tomlファイルの中身はこんな感じになっています。

build.toml
# This file is auto generated by SAM CLI build command

[function_build_definitions]
[function_build_definitions.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx]
codeuri = "/Users/[Your Directory]/apigw_lambda_dynamodb_sample/src"
runtime = "python3.9"
architecture = "x86_64"
handler = "app.lambda_handler"
manifest_hash = ""
packagetype = "Zip"
functions = ["MyFunction"]

[layer_build_definitions]

12.デプロイ

ターミナル
$ sam deploy --guided
# 実行結果
Configuring SAM deploy
======================

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

	Setting default arguments for 'sam deploy'
	=========================================
	Stack Name [sam-app]: apigw-lambda-dynamodb-sample
	AWS Region [us-east-1]: 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]: N
	MyFunction 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-xxxxxxxxxxxx
	 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 apigw-lambda-dynamodb-sample/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  336 / 336  (100.00%)

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

Initiating deployment
=====================
Uploading to apigw-lambda-dynamodb-sample/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.template  1049 / 1049  (100.00%)

Waiting for changeset to be created..
CloudFormation stack changeset
-------------------------------------------------------------------------------------------------
Operation                LogicalResourceId        ResourceType             Replacement
-------------------------------------------------------------------------------------------------
+ Add                    MyDynamoDBTable          AWS::DynamoDB::Table     N/A
+ Add                    MyFunctionApiEventPerm   AWS::Lambda::Permissio   N/A
                         issionProd               n
+ Add                    MyFunctionRole           AWS::IAM::Role           N/A
+ Add                    MyFunction               AWS::Lambda::Function    N/A
+ Add                    ServerlessRestApiDeplo   AWS::ApiGateway::Deplo   N/A
                         ymentxxxxxxxxxx          yment
+ Add                    ServerlessRestApiProdS   AWS::ApiGateway::Stage   N/A
                         tage
+ Add                    ServerlessRestApi        AWS::ApiGateway::RestA   N/A
                                                  pi
-------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:[Your Account Id]:changeSet/samcli-deployxxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx


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

2022-11-07 18:20:08 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 0.5 seconds)
-------------------------------------------------------------------------------------------------
ResourceStatus           ResourceType             LogicalResourceId        ResourceStatusReason
-------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS       AWS::CloudFormation::S   apigw-lambda-dynamodb-   User Initiated
                         tack                     sample
CREATE_IN_PROGRESS       AWS::DynamoDB::Table     MyDynamoDBTable          -
CREATE_IN_PROGRESS       AWS::DynamoDB::Table     MyDynamoDBTable          Resource creation
                                                                           Initiated
CREATE_COMPLETE          AWS::DynamoDB::Table     MyDynamoDBTable          -
CREATE_IN_PROGRESS       AWS::IAM::Role           MyFunctionRole           -
CREATE_IN_PROGRESS       AWS::IAM::Role           MyFunctionRole           Resource creation
                                                                           Initiated
CREATE_COMPLETE          AWS::IAM::Role           MyFunctionRole           -
CREATE_IN_PROGRESS       AWS::Lambda::Function    MyFunction               -
CREATE_IN_PROGRESS       AWS::Lambda::Function    MyFunction               Resource creation
                                                                           Initiated
CREATE_COMPLETE          AWS::Lambda::Function    MyFunction               -
CREATE_IN_PROGRESS       AWS::ApiGateway::RestA   ServerlessRestApi        -
                         pi
CREATE_IN_PROGRESS       AWS::ApiGateway::RestA   ServerlessRestApi        Resource creation
                         pi                                                Initiated
CREATE_COMPLETE          AWS::ApiGateway::RestA   ServerlessRestApi        -
                         pi
CREATE_IN_PROGRESS       AWS::Lambda::Permissio   MyFunctionApiEventPerm   -
                         n                        issionProd
CREATE_IN_PROGRESS       AWS::ApiGateway::Deplo   ServerlessRestApiDeplo   -
                         yment                    ymentxxxxxxxxxx
CREATE_IN_PROGRESS       AWS::Lambda::Permissio   MyFunctionApiEventPerm   Resource creation
                         n                        issionProd               Initiated
CREATE_IN_PROGRESS       AWS::ApiGateway::Deplo   ServerlessRestApiDeplo   Resource creation
                         yment                    ymentxxxxxxxxxx          Initiated
CREATE_COMPLETE          AWS::ApiGateway::Deplo   ServerlessRestApiDeplo   -
                         yment                    ymentxxxxxxxxxx
CREATE_IN_PROGRESS       AWS::ApiGateway::Stage   ServerlessRestApiProdS   -
                                                  tage
CREATE_IN_PROGRESS       AWS::ApiGateway::Stage   ServerlessRestApiProdS   Resource creation
                                                  tage                     Initiated
CREATE_COMPLETE          AWS::ApiGateway::Stage   ServerlessRestApiProdS   -
                                                  tage
CREATE_COMPLETE          AWS::Lambda::Permissio   MyFunctionApiEventPerm   -
                         n                        issionProd
CREATE_COMPLETE          AWS::CloudFormation::S   apigw-lambda-dynamodb-   -
                         tack                     sample
-------------------------------------------------------------------------------------------------
CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------------
Outputs
-------------------------------------------------------------------------------------------------
Key                 Api
Description         API Gateway endpoint URL
Value               https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/src/
-------------------------------------------------------------------------------------------------

Successfully created/updated stack - apigw-lambda-dynamodb-sample in ap-northeast-1

13.この時点でのフォルダの中身を把握

フォルダ内
 apigw_lambda_dynamodb_sample/
   ├── samconfig.toml[New!!]
   ├── .aws-sam/
   │   ├── build.toml
   │   └── build/
   │       ├── template.yaml
   │       └── MyFunction/
   │           └── app.py
   ├── src/
   │   └── app.py
   └── template.yaml

14.結果を確認

※[出力されているURLによって異なります]部分はOutput結果を見て変更して実行ください。

ターミナル
$ curl https://[出力されているURLによって異なります].execute-api.ap-northeast-1.amazonaws.com/Prod/src/
# 実行結果
{"message": "Data insertion succeeded!!!!!!!!!"}

想定通りの結果が返ってきました。

15.DynamoDB→"項目の探索"を確認(コンソール画面)


無事データ挿入出来ています。

16.念の為、samconfig.tomlファイルの中身はこんな感じになっています。

samconfig.toml
version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "apigw-lambda-dynamodb-sample"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxxxx"
s3_prefix = "apigw-lambda-dynamodb-sample"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []

17.削除(お片付け)

ターミナル
$ sam delete
# 実行結果
	Are you sure you want to delete the stack apigw-lambda-dynamodb-sample in the region ap-northeast-1 ? [y/N]: y
	Are you sure you want to delete the folder apigw-lambda-dynamodb-sample in S3 which contains the artifacts? [y/N]: y
	- Deleting S3 object with key apigw-lambda-dynamodb-sample/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	- Deleting S3 object with key apigw-lambda-dynamodb-sample/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.template
	- Deleting Cloudformation stack apigw-lambda-dynamodb-sample

Deleted successfully

※CloudFormationコンソールを確認すると「aws-sam-cli-managed-default」というAWS SAMのテンプレートを保存するバケットとバケットポリシーを作成するスタックが残りますが、これを削除するかどうかはお任せします。削除しても次回sam deployする際、新規で再作成されます。今回のハンズオン内容外のリソースと仮に紐づいていた場合や既に「aws-sam-cli-managed-default」が作業リージョンにある状態で着手した方は慎重にご確認ください。残しておいても害はないと思います。

※ローカルのフォルダを削除する場合は親フォルダである「apigw_lambda_dynamodb_sample」フォルダごと削除して問題ありません。
(コンソールからもスタックは削除出来ますが、sam deleteコマンドでの削除がまだであれば、リソースの削除後である事をお勧めします。)

以上でした。

有難うございました。

Discussion