#ハンズオン(AWS API gateway, Lambda, dynamoDB)
「Lambda未経験者限定」の超入門編です。なるべく図表を多用して書きます。分からなかったところは教えてください、補足を書き足します。60分でひと通り試すことができます。
##ゴール設定
自分の言葉で「サーバーレスって何?」を話せるようにするために、サーバーレスで典型的なAWS Lambdaの構成を30分で試せる最もシンプルなデータの書き込みと読み込みを仮想サーバー無しでやってみます。
##必要なもの
- パソコン
- 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管理コンソールにログインして、下図のシステム構成を作ります。
ではここからハンズオンスタート。
##(1)dynamoDB(まずデータを用意します)
dynabmoDB[テーブル]を作って、レコードに相当する[項目(Item)]を定義します。ここではオンプレに慣れた人向けに図を書いていますが、Dataの部分は、正しくは「属性(attribute)」と呼びます。
###(1-1)テーブルを作成する。
AWS管理コンソールからDynamoDB[テーブルの作成]を実行します。
[テーブル名」と[パーティションキー]に好きな名前を付けて[作成]を実行します。
空っぽのDynamoDB[テーブル]ができました。次は自分のテーブルをクリックしてデータを書いてみます。
###(1-2)データを書く。
用語が紛らわしいのでdynamoDBの図を見ながら進めてください。リレーショナルDBでいうデータレコードを1つ書きたいのですが、dynamoDBでは項目とかアイテムとかいいます。そしてデータカラムに相当するのが属性っていいます。しっくりこないです。さて、データレコードを書き込み、言い直しすると項目(アイテム)を追加したいので[項目タブ]→[項目の作成]を実行します。
##(2)Lambda(とりあえずデータを読んでみます)
いよいよ、DynamoDBに書き込んだデータ[項目(アイテム)]をLambdaで読み込みます。ここでは[Lambda関数]を作ります。関連する設定が幾つかあります。実行IAMロールの設定は必須。その他はオプションなので必要に応じて設定します~ 例えば: VPC内で使うための設定。コードの外に環境変数を持つ場合。PHP用SDKやpythonなどの外部ライブラリはZipファイルにまとめてアップロードできます。
###(2-1)こんちわ
では、AWS管理コンソールでLambdaを見つけて[関数の作成]を実行します。
実行IAMロールは[新しくIAMロールを作る]もしくは[既存IAMロールを使う]から適宜選んでください。IAMロールに与えるポリシーは、今回はお試しなので[Lambda]と[DynamoDB]のそれぞれフルアクセス権限とします。本番では最低限に調整します。
###(2-2)データを読む。
Lambda関数コードを書きます。最後に[保存]を実行。
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)
}
”成功”って表示されたらHappy。詳細をクリックすると実行結果のデータが表示されます。
##(3)API gateway(APIを体験します)
今度は、WEBブラウザのURLでLambdaにアクセスして、データをブラウザに表示します。準備するのはAPI Gateway。
###(3-1)WebブラウザでHTTPSアクセスする。
Lambdaを編集したDesignerという画面で[+ トリガーを追加]を実行して、下図を参考にAPIを設定する。
WEBブラウザでLambdaを起動してみよう。下図をクリック。
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です。
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ポリシーでブロックされている、とある。
API Gateway のクロスオリジンリソース共有で、他のサイトからのアクセスを許可する。
##APIで得たjsonをWEBブラウザに表示したい
フロントエンド側で静的ファイルをWEBブラウザで表示する(apacheで実行)。
<!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引数を受け取って、現在時刻を自動取得して、で、書き込む。
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
}