Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Lambda、APIGateway、Ajaxの作業メモ

htmlのWebフォームの入力内容をAjaxで通信しLambdaに送り結果をまた受け取るありがちな処理を実装 その際に色々と躓いたのでまとめたメモ ※ 注意:メモを書いてから少し時間が経っているので一部で怪しい部分があり

前提・実現したいことの流れ

  1. HTMLのフォームに名前とメールアドレスを入力しAPIGatewayへ
  2. APIGatewayが受け取りLambdaへフォーム内容を渡す
  3. Lambdaは受け取った名前やアドレスを扱ってなんらかの処理(例えばDB書き込みやメールを送るなどだがここの処理は割愛)
  4. Lambdaは通信結果をAPIGatewayへ
  5. HTMLはAjaxで結果を受け取る

図解するとこんな感じ

html<--- API Gateway --> Lambda

作成手順

1.Lambda関数:

設計図から[microservice-http-endpoint-python3]を選択 関数名は今回は「Test」とする

2.API Gateway:

Lambda関数を作成時に自動生成だとメソッド: ANYになりCORSが有効にして効かない不具合が あるため、ANYを削除しPOSTで新たにメソッドを作成

2-1.階層

階層は以下のようになっている想定

/
-/Test
--POST

2-2. セットアップ(POST - セットアップ)

  1. 統合タイプ-Lambda 関数を選択
  2. Lambda プロキシ統合の使用-今回はチェックを入れない
  3. Lambda リージョン-適切なものを選択
  • アジアパシフィック(東京)なのでap-northeast-1
  1. Lambda 関数
  • Test
  1. デフォルトタイムアウトの使用
  • チェック

2-3.CORSの有効化

アクションのプルダウンメニューで以下の順に実行

  1. リソースのアクション-CORSの有効化
  2. APIアクション-APIのデプロイ
  3. デプロイ

2-4.メソッドリクエスト

※ ここの設定が少々怪しいので要検証

--URL クエリ文字列パラメータ
---path
--HTTP リクエストヘッダー
---Content-Type

2-5.統合リクエスト

--本文マッピングテンプレート
---テンプレートが定義されていない場合 (推奨) をチェック
---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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment