AWS Lambda + API Gateway で作るサーバーレス問い合わせ機能


静的ページ用の問い合わせ機能を、AWS Lambda + API Gateway (+ Amazon SES) でサーバーレスに実装する手順を整理します。

GitHubのソースコードはこちら

手順

設計の全体像は、クライアントから API Gateway の POST メソッドを呼び出し、それをトリガーに Lambda 関数を発火させて、SES の送信用メールアドレスで管理者にメール通知をおこなう感じです。

1. Amazon SES

まずは問い合わせ内容を通知するためのメールアドレスの設定です。

メールアドレスの追加・認証

Amazon SESの管理画面で、送信用のメールアドレスを追加し、届いたメールから認証を完了させます。

ドメイン用 DKIM の設定

設定したアドレスからSESでメールを送信する時に、送信元アドレスとして [email protected] via amazon.com のように via amazon.com と表記されることがあります。

この via amazon.com を消すために DKIM の設定をします。

Amazon SESの管理画面から送信用アドレスの詳細ページにいき、「DKIM」のCNAMEの値を入手します。

このCNAMEの3つをメールアドレスのドメインのDNSレコードに追加します。

2. AWS Lambda

続いて、問い合わせ通知の処理を AWS Lambda で実装します。

IAMロール

まずは IAMの管理画面で今回の Lambda に適用するロールを作成します。

ロールは以下のJSONで規定します。


{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
    ,{
       "Effect": "Allow",
       "Action": ["ses:Send*"],
       "Resource":"*"
     }
  ]
}

Lambda 関数の作成

Lambda の管理画面で新しい関数を作成します。アクセス権限には、先ほど作成したロールを割り当てます。

index.js の更新

index.js を次のように更新します。region:Source はご自身の情報に修正してください。

index.js
'use strict'
const SDK = require('aws-sdk')

exports.handler = (event, context, callback) => {
    const ses = new SDK.SES({ region: 'ap-southeast-2' })
    const email = {
        // From
        Source: "YOUR_EMAIL_ADDRESS",
        // To
        Destination: { ToAddresses: [event.form.to] },
        Message: {
            Subject: { Data: event.form.subject },
            Body: {
                Text: { Data: event.form.body }
            },
        },
    };
    ses.sendEmail(email, callback);
};

3. API Gateway

最後に API Gateway で、問い合わせを受け付けるエンドポイントを作ります。

API の新規作成

上で作成した Lambda 関数のページの「トリガーを追加」で API Gateway の REST API を新規作成します。

リソースの追加

作成後、同 REST API のページに自動的に移動します。

「アクション > リソースの追加」で、/send など、任意のリソースを追加します。

POST メソッドの追加

「アクション > メソッドの追加」で、追加したリソースに POST メソッドを追加します。

POST メソッドの設定

リクエストマッピングテンプレート

POST メソッドの詳細ページ「統合リクエスト > マッピングテンプレート」で application/json のマッピングテンプレートを追加します。テンプレートの記載内容は次の通りです。

application/json
{
    "form": $input.json('$')
}
レスポンスヘッダー

POST メソッドの詳細ページ「メソッドレスポンス > 200 のレスポンスヘッダー」で Access-Control-Allow-Origin というヘッダーを追加します。

その後、「統合レスポンス > ヘッダーのマッピング」で次のように値をセットします。

レスポンスヘッダー マッピングの値
Access-Control-Allow-Origin '*'

上記設定がないと、僕の環境下では、クライアントから呼び出した時に

No 'Access-Control-Allow-Origin' header is present on the requested resource

のエラーが出ました。この Access-Control-Allow-Origin の設定で解決できました。

API のデプロイ

「アクション > API のデプロイ」で、任意のステージ(v1 など)に REST API をデプロイします。

ステージの「URL の呼び出し」にエンドポイントの記載があります。

POST https://xxxxxx.execute-api.YOUR_REGION.amazonaws.com/v1/YOUR_API_NAME/send

このエンドポイントで作成した POST メソッドを呼び出せます。

4. クライアントでの呼び出し

静的ページから POST リクエストで API Gateway のエンドポイントを呼ぶことで、Lambda 関数が発火します。

jQuery で利用する場合、次のように呼び出します。


function submitContact(url, to, subject, body) {
  const jsonData = JSON.stringify({
    'to':      to,
    'subject': subject,
    'body':    body
  })

  $.ajax({
    type: "POST",
    url:   url,
    async: true,
    contentType: 'application/json',
    dataType: 'json',
    data: jsonData,
    error: function(data) { 
      console.log(data)
    },
    success: function(data) {
      console.log(data)
    }
  })
}

References