LoginSignup
18
14

More than 3 years have passed since last update.

図解で、ハンズオン(AWS API gateway, Lambda, dynamoDB)

Posted at

ハンズオン(AWS API gateway, Lambda, dynamoDB)

「Lambda未経験者限定」の超入門編です。なるべく図表を多用して書きます。分からなかったところは教えてください、補足を書き足します。60分でひと通り試すことができます。

ゴール設定

自分の言葉で「サーバーレスって何?」を話せるようにするために、サーバーレスで典型的なAWS Lambdaの構成を30分で試せる最もシンプルなデータの書き込みと読み込みを仮想サーバー無しでやってみます。
image.png

必要なもの

  • パソコン
  • AWSアカウント
  • サーバレスって何という疑問

目次

  • (1)dynamoDB(まずデータを用意します
    • (1-1)テーブルを作成する。
    • (1-2)データを書く。
  • (2)Lambda(とりあえずデータを読んでみます
    • (2-1)こんちわ
    • (2-2)データを読む。
  • (3)API gateway(APIを体験します
    • (3-1)WebブラウザでHTTPSアクセスする。
    • (3-2)Lambda再び(ついでなのでデータを書いてみます

アーキテクチャ

AWS管理コンソールにログインして、下図のシステム構成を作ります。
image.png

ではここからハンズオンスタート。

(1)dynamoDB(まずデータを用意します

dynabmoDB[テーブル]を作って、レコードに相当する[項目(Item)]を定義します。ここではオンプレに慣れた人向けに図を書いていますが、Dataの部分は、正しくは「属性(attribute)」と呼びます。
image.png

(1-1)テーブルを作成する。

AWS管理コンソールからDynamoDB[テーブルの作成]を実行します。
image.png

[テーブル名」と[パーティションキー]に好きな名前を付けて[作成]を実行します。
image.png

空っぽのDynamoDB[テーブル]ができました。次は自分のテーブルをクリックしてデータを書いてみます。
image.png

(1-2)データを書く。

用語が紛らわしいのでdynamoDBの図を見ながら進めてください。リレーショナルDBでいうデータレコードを1つ書きたいのですが、dynamoDBでは項目とかアイテムとかいいます。そしてデータカラムに相当するのが属性っていいます。しっくりこないです。さて、データレコードを書き込み、言い直しすると項目(アイテム)を追加したいので[項目タブ]→[項目の作成]を実行します。
image.png

もう一度いいます、用語に気を付けて最初のデータを書きます。
image.png

項目(アイテム)を2つ追加したときの例
image.png

(2)Lambda(とりあえずデータを読んでみます

いよいよ、DynamoDBに書き込んだデータ[項目(アイテム)]をLambdaで読み込みます。ここでは[Lambda関数]を作ります。関連する設定が幾つかあります。実行IAMロールの設定は必須。その他はオプションなので必要に応じて設定します~ 例えば: VPC内で使うための設定。コードの外に環境変数を持つ場合。PHP用SDKやpythonなどの外部ライブラリはZipファイルにまとめてアップロードできます。
image.png

(2-1)こんちわ

では、AWS管理コンソールでLambdaを見つけて[関数の作成]を実行します。
image.png

続いて、下図を参考に設定します。
image.png

実行IAMロールは[新しくIAMロールを作る]もしくは[既存IAMロールを使う]から適宜選んでください。IAMロールに与えるポリシーは、今回はお試しなので[Lambda]と[DynamoDB]のそれぞれフルアクセス権限とします。本番では最低限に調整します。
image.png

(2-2)データを読む。

Lambda関数コードを書きます。最後に[保存]を実行。
image.png

lambda_function.py
import json
import boto3

def lambda_handler(event, context):
    # テーブル定義
    table_name = 'KanoTable'
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(table_name)

    # レコード読み出し
    response = table.get_item( 
        Key = { 
            'TargetKey': 'kano',
            'TimeStamp': '20200107 23:07' 
        } 
    )

    print(response)

    return {
        'statusCode': 200,
        'headers': { 'Content-type': 'application/json;charset=UTF-8' },
        'body': json.dumps(response)
    }

データの読み込みを[テスト]してみよう。
image.png

”成功”って表示されたらHappy。詳細をクリックすると実行結果のデータが表示されます。
image.png

(3)API gateway(APIを体験します

今度は、WEBブラウザのURLでLambdaにアクセスして、データをブラウザに表示します。準備するのはAPI Gateway。
image.png

(3-1)WebブラウザでHTTPSアクセスする。

Lambdaを編集したDesignerという画面で[+ トリガーを追加]を実行して、下図を参考にAPIを設定する。
image.png

WEBブラウザでLambdaを起動してみよう。下図をクリック。
image.png

WEBブラウザにJSON形式のデータが表示されたら、とりあえずDynamoDBのデータ読み出しが成功とする。

{"Item": 
  {"Content": "\u6700\u521d\u306e\u30ec\u30b3\u30fc\u30c9\u3060\u3088", 
  "TimeStamp": "20200107 23:07",
  "TargetKey": "kano"},
  "ResponseMetadata": 
     {"RequestId": "1A5*****SUAAJG",
      "HTTPStatusCode": 200,
      "HTTPHeaders": {略}, "RetryAttempts": 0}}

(3-2)Lambda再び(ついでなのでデータを書いてみます

ここは復習編。再び(2-1)から順に新しいLambda関数を作成します。今度はデータを書くLambdaです。

putRecordDynamoDB.py
import json
import boto3

def lambda_handler(event, context):

    # テーブルを定義
    table_name = 'KanoTable'
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(table_name) 

    # レコード書き出し
    response = table.put_item( 
        Item = { 
            'TargetKey': 'new',
            'TimeStamp': 'du',
            'Content': '追加しました'
        } 
    )

    return {
        'statusCode': 200,
        'body': json.dumps('Record Added!')
    }

まとめ

世の中でサーバーレスと言われている典型的な「API Gateway」「Lambda」「dynamoDB」の3つを組み合わせて、データを書いて、読むというWEBシステムの基本的なプログラミングを体験できたと思います(できました?)。準備含めて60分でハンズオンする内容なのでもやもや感はあるかと思います。この後は時間をかけて、データ入力用のHTMLファイルとデータを整形して表示するHTMLファイルを作成してS3などに保存して、そのHTMLからWEBブラウザを起動すれば、簡単な掲示板アプリみたいなのを作れると思います。

以上、おしまい。

.
.
.
.
.
.
.
.

以下、参考。

トラブルシューティング

CORS(Cross-Origin resource sharing) オリジン間リソース共有が問題?

WEBブラウザの開発者ツールでデバッグ。CORSポリシーでブロックされている、とある。
image.png

API Gateway のクロスオリジンリソース共有で、他のサイトからのアクセスを許可する。
image.png

APIで得たjsonをWEBブラウザに表示したい

フロントエンド側で静的ファイルをWEBブラウザで表示する(apacheで実行)。

lambda_get.html
<!DOCTYPE html>
<html lang="ja">
<html>
  <head>
  <meta charset="UTF-8">
  <title>Lambda json 読み出し</title>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
    <script>
      window.onload=function(){
        $.ajax( {
          type: "get",
          dataType: "json",
          url : "https://d6****y5.execute-api.ap-northeast-1.amazonaws.com/default/getRecordDynamoDB",
          success : function( json ){
            console.log(json)
            //console.log(json.Item.Content);     //1アイテムの場合
            //console.log(json.Items[0].Content); //複数アイテムの場合
            $("#msg-result").text("success: "+json.Count+" pcs");

            strTemp = "<table border=1>";
            json.Items.forEach( function(dbitems) {
              strTemp += "<tr><td>"+ dbitems.Content +"</td>";
              strTemp += "<td>"+ dbitems.TargetKey + "</td>";
              strTemp += "<td>"+ dbitems.TimeStamp + "</td></tr>";
            });
            strTemp += "</table>";
            $("#msg").html( strTemp );

          },
          error : function (xhr,text,thrown){
            $("#msg-result").text("error : "+text);
          }
        });
      }
    </script>

  </head>
  <body>

    <h1>dynamoDBからアイテムを読み出し</h1>
    <p id="msg-result">問合せ中...</p>
    <div id="msg">問合せ中...</div>

  </body>
</html>

DBに書き込む値をWEBブラウザの引数で渡す場合

WEBブラウザのURL入力をこんな(↓)引数で渡したいので

# ブラウザの場合
https://xxxxxx.amazonaws.com/putRecordDynamoDB?Key=Ichiro&Content=(^^)%20/~~~
# linuxの場合(&でなく\&)
curl https://xxxxxx.amazonaws.com/putRecordDynamoDB?Key=Ichiro\&Content=(^^)%20/~~~

lambda関数コードを改造する。event引数を受け取って、現在時刻を自動取得して、で、書き込む。

putRecordDynamoDB.py
import json
import boto3
import datetime

def lambda_handler(event, context):

    # テーブルを定義
    table_name = 'KanoTable'
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(table_name) 

    try:
        strKey = event['queryStringParameters']['Key']
        strMsg = event['queryStringParameters']['Content']
        strNow = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        # レコード書き出し
        response = table.put_item( 
            Item = { 
                'TargetKey': strKey,
                'TimeStamp': strNow,
                'Content': strMsg
            } 
        )
        return {
            'statusCode': 200,
            'body': json.dumps('Record Added!')
        }
    except:
        print(event) #デバッグ用eventの中身をcloudwatchに出力
        strTemp = "please send two data: ?Key='abc'&Content='def'"
        print(strTemp)
        return {
            'statusCode': 400,
            'body': json.dumps(strTemp)
        }

eventのパラメータを得るには、cloudwatchログを眺めて引数で渡した[Key]とか[Content]辺りから見つける。

{
'version': 2, 'path': '/default/putRecordDynamoDB', 'httpMethod': 'GET', 

   <中略>

 'queryStringParameters': {'Content': '(^^)', 'Key': 'Ichiro\\'}, 'multiValueQueryStringParameters': {'Content': ['(^^)'], 'Key': ['Ichiro\\']},

   <中略>

 'body': None, 'isBase64Encoded': True
}
18
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
14