htmlのWebフォームの入力内容をAjaxで通信しLambdaに送り結果をまた受け取るありがちな処理を実装 その際に色々と躓いたのでまとめたメモ ※ 注意:メモを書いてから少し時間が経っているので一部で怪しい部分があり
- HTMLのフォームに名前とメールアドレスを入力しAPIGatewayへ
- APIGatewayが受け取りLambdaへフォーム内容を渡す
- Lambdaは受け取った名前やアドレスを扱ってなんらかの処理(例えばDB書き込みやメールを送るなどだがここの処理は割愛)
- Lambdaは通信結果をAPIGatewayへ
- HTMLはAjaxで結果を受け取る
html<--- API Gateway --> Lambda
設計図から[microservice-http-endpoint-python3]を選択 関数名は今回は「Test」とする
Lambda関数を作成時に自動生成だとメソッド: ANYになりCORSが有効にして効かない不具合が あるため、ANYを削除しPOSTで新たにメソッドを作成
階層は以下のようになっている想定
/
-/Test
--POST
- 統合タイプ-Lambda 関数を選択
- Lambda プロキシ統合の使用-今回はチェックを入れない
- Lambda リージョン-適切なものを選択
- アジアパシフィック(東京)なのでap-northeast-1
- Lambda 関数
- Test
- デフォルトタイムアウトの使用
- チェック
アクションのプルダウンメニューで以下の順に実行
- リソースのアクション-CORSの有効化
- APIアクション-APIのデプロイ
- デプロイ
※ ここの設定が少々怪しいので要検証
--URL クエリ文字列パラメータ
---path
--HTTP リクエストヘッダー
---Content-Type
--本文マッピングテンプレート
---テンプレートが定義されていない場合 (推奨) をチェック
---Content-Type
----application/jsonに
-----テテンプレート
※ここを適当にして本当にハマりました。
参考:API Gatewayへの入力値にLambdaからアクセスする こちらの記事が非常に参考
ここで渡ってくるデータを指定するので必ず設定が必要です。
テンプレートの例
{
"accountId": "$context.identity.accountId",
"apiId": "$context.apiId",
"apiKey": "$context.identity.apiKey",
"caller": "$context.identity.caller",
"headers": {
#foreach( $key in $input.params().header.keySet() )
"$key": "$input.params().header.get($key)"#if( $foreach.hasNext ),#end
#end
},
"httpMethod": "$context.httpMethod",
"path": "$context.resourcePath",
"pathParameters": {
#foreach( $key in $input.params().path.keySet() )
"$key": "$input.params().path.get($key)"#if( $foreach.hasNext ),#end
#end
},
"queryParameters": {
#foreach( $key in $input.params().querystring.keySet() )
"$key": "$input.params().querystring.get($key)"#if( $foreach.hasNext ),#end
#end
},
"requestId": "$context.requestId",
"requestParameters": $input.json('$'),
"resourceId": "$context.resourceId",
"sourceIp": "$context.identity.sourceIp",
"stage": "$context.stage",
"user": "$context.identity.user",
"userAgent": "$context.identity.userAgent",
"userArn": "$context.identity.userArn"
}
lambda側の関数
import json
import urllib
def lambda_handler(event, context):
#print(json.dumps(event, indent=4))
try:
# フォームに入力されたデータを得る
param = urllib.parse.parse_qs(event['requestParameters'])
username = param['username'][0]
email = param['email'][0]
# クライアントのIPを 得る
host = event['sourceIp']
# 結果を返す
return {
'statusCode' : 200,
'headers' : {
'access-control-allow-origin' : '*',
'content-type' : 'application/json'
},
'data' : {'email' : email},
'completed' : 1
}
except:
import traceback
traceback.print_exc()
return {
'statusCode' : 200,
'headers' : {
'access-control-allow-origin' : '*',
'content-type' : 'application/json'
},
'completed' : 0
}
フォーム側のJavaScriptとフォームのhtmlになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>jqueryのajaxのサンプル</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$( function() {
var apiUrl = 'https://xxxxxxxxxxx/Test';
$('#button').click(
function(){
var formData = $("#form").serialize();
console.log("formData:" + formData);
$.ajax({
url:apiUrl, // 通信先のURL
type:'POST',// 使用するHTTPメソッド (GET/ POST)
data:formData, // 送信するデータ
dataType:'json', // 応答のデータの種類 (xml/html/script/json/jsonp/text)
contentType: "application/json",
// 通信に成功した時に実行される
}).done(function(response,textStatus,jqXHR) {
console.log("成功:" + jqXHR.status);
if (response.completed == 1)
{
$('#message').html('登録を完了しました。');
console.log(response.data.email);
}
else if(response.completed == 0)
{
$('#message').html('サーバーの内部エラーのため登録が失敗しました。');
}
// 通信に失敗した時に実行される
}).fail(function(jqXHR, textStatus, errorThrown) {
alert("失敗:" + jqXHR.status);
console.log("失敗:" + jqXHR.status);
});
});
});
</script>
</head>
<body>
<form id="form" action="">
<input type="button" id="button" value="開始ボタン"><br/>
氏名<input type="text" name="username"><br />
メールアドレス<input type="text" name="email"><br />
</form>
<div id="message"></div>
</body>
</html>