静的サイトのサーバーレスお問い合わせフォームの作成

公開: 2022-03-10
簡単な要約↬この記事の助けを借りて、サーバーレスフレームワークで独自の静的サイトメーラーを構築するのに役立つAmazon Web Services(AWS)LambdaおよびSimple Email Service(SES)APIの基本を最終的に学ぶことができます。 始めましょう!

静的サイトジェネレーターは、WordPressのようなコンテンツ管理システム(CMS)の高速でシンプルな代替手段を提供します。 サーバーやデータベースのセットアップはなく、ビルドプロセスと単純なHTML、CSS、JavaScriptだけがあります。 残念ながら、サーバーがなければ、すぐに限界に達するのは簡単です。 たとえば、お問い合わせフォームを追加する場合です。

サーバーレスアーキテクチャの台頭により、静的サイトに連絡フォームを追加することが、CMSに切り替える理由である必要はなくなりました。 両方の長所を活かすことができます。連絡先フォーム用のサーバーレスバックエンドを備えた静的サイトです(保守する必要はありません)。 おそらく何よりも、ポートフォリオのようなトラフィックの少ないサイトでは、多くのサーバーレスプロバイダーの上限により、これらのサービスは完全に無料になります。

この記事では、サーバーレスフレームワーク上で独自の静的サイトメーラーを構築するためのAmazon Web Services(AWS)LambdaおよびSimple Email Service(SES)APIの基本を学習します。 フルサービスは、AJAXリクエストから送信されたフォームデータを受け取り、Lambdaエンドポイントに到達し、データを解析してSESパラメーターを構築し、メールアドレスを送信して、ユーザーに応答を返します。 デプロイを通じてサーバーレスを初めてセットアップする方法を説明します。 完了するまでに1時間もかからないので、始めましょう。

静的サイトフォーム。メッセージをLambdaエンドポイントに送信し、ユーザーに応答を返します。
静的サイトフォーム。メッセージをLambdaエンドポイントに送信し、ユーザーに応答を返します。
ジャンプした後もっと! 以下を読み続けてください↓

セットアップ

サーバーレステクノロジーの使用を開始するには、最小限の前提条件があります。 私たちの目的では、これはYarn、サーバーレスフレームワーク、およびAWSアカウントを備えた単なるノード環境です。

プロジェクトの設定

Serverless FrameworkWebサイト。インストールとドキュメント化に役立ちます。
Serverless FrameworkWebサイト。 インストールとドキュメント化に役立ちます。

Yarnを使用して、ServerlessFrameworkをローカルディレクトリにインストールします。

  1. プロジェクトをホストするための新しいディレクトリを作成します。
  2. コマンドラインインターフェイスでディレクトリに移動します。
  3. このプロジェクトのpackage.jsonファイルを作成するには、 yarn initを実行します。
  4. yarn add serverlessを実行して、フレームワークをローカルにインストールします。
  5. yarn serverless create --template aws-nodejs --name static-site-mailerを実行して、ノードサービステンプレートを作成し、 static-site-mailerという名前を付けます。

プロジェクトはセットアップされていますが、AWSサービスをセットアップするまで何もできません。

アマゾンウェブサービスアカウント、クレデンシャル、およびシンプルなメールサービスの設定

アマゾンウェブサービスのサインアップページには、寛大な無料利用枠が含まれており、プロジェクトを完全に無料にすることができます。
アマゾンウェブサービスのサインアップページには、寛大な無料利用枠が含まれており、プロジェクトを完全に無料にすることができます。

Serverless Frameworkは、AWSクレデンシャルを設定するためのビデオウォークスルーを記録していますが、ここにも手順を示しました。

  1. AWSアカウントにサインアップするか、すでにアカウントをお持ちの場合はログインしてください。
  2. AWS検索バーで、「IAM」を検索します。
  3. IAMページで、サイドバーの[ユーザー]をクリックしてから、[ユーザーの追加]ボタンをクリックします。
  4. [ユーザーの追加]ページで、ユーザーに名前を付けます。「サーバーレス」などが適切です。 [アクセスの種類]で[プログラムによるアクセス]をオンにして、[次へ]をクリックします。
  5. アクセス許可画面で、[既存のポリシーを直接添付する]タブをクリックし、リストで[AdministratorAccess]を検索して確認し、[次へ]をクリックします。
  6. レビュー画面に、「プログラムによるアクセス」と「AdministratorAccess」の付いたユーザー名が表示されたら、ユーザーを作成します。
  7. 確認画面には、ユーザーの「アクセスキーID」と「シークレットアクセスキー」が表示されます。これらは、ServerlessFrameworkにアクセスを提供するために必要です。 CLIで、 yarn sls config credentials --provider aws --key YOUR_ACCESS_KEY_ID --secret YOUR_SECRET_ACCESS_KEYと入力し、 YOUR_ACCESS_KEY_IDYOUR_SECRET_ACCESS_KEYを確認画面のキーに置き換えます。

これでクレデンシャルが設定されましたが、AWSコンソールでSimple EmailServiceを設定しましょう。

  1. 左上隅にある[コンソールホーム]をクリックして、ホームに戻ります。
  2. ホームページのAWS検索バーで、「SimpleEmailService」を検索します。
  3. SESホームページで、サイドバーの「メールアドレス」をクリックします。
  4. [メールアドレス]リストページで、[新しいメールアドレスを確認する]ボタンをクリックします。
  5. ダイアログウィンドウで、メールアドレスを入力し、[このメールアドレスを確認]をクリックします。
  6. アドレスを確認するためのリンクが記載されたメールがすぐに届きます。 リンクをクリックしてプロセスを完了します。

アカウントが作成されたので、サーバーレステンプレートファイルを見てみましょう。

サーバーレスフレームワークのセットアップ

serverless createを実行すると、2つのファイルが作成されます。Lambda関数を含むhandler.jsと、サーバーレスアーキテクチャ全体の構成ファイルであるserverless.ymlです。 構成ファイル内で、必要な数のハンドラーを指定できます。各ハンドラーは、他の関数と対話できる新しい関数にマップされます。 このプロジェクトでは、単一のハンドラーのみを作成しますが、完全なサーバーレスアーキテクチャでは、サービスのさまざまな機能のいくつかを使用できます。

handler.jsとserverless.ymlを含むServerlessFrameworkから生成されたデフォルトのファイル構造。
handler.jsとserverless.ymlを含むServerlessFrameworkから生成されたデフォルトのファイル構造。

handler.jsには、 helloという名前の単一のエクスポートされた関数が表示されます。 これは現在、主要な(そして唯一の)機能です。 これは、すべてのノードハンドラーとともに、次の3つのパラメーターを取ります。

  • event
    これは、関数の入力データと考えることができます。
  • context object
    これには、Lambda関数の実行時情報が含まれています。
  • callback
    呼び出し元に情報を返すためのオプションのパラメーター。
 // handler.js 'use strict'; module.exports.hello = (event, context, callback) => { const response = { statusCode: 200, body: JSON.stringify({ message: 'Go Serverless v1.0! Your function executed successfully!', input: event, }), }; callback(null, response); };

helloの下部に、コールバックがあります。 応答を返すためのオプションの引数ですが、明示的に呼び出されていない場合は、暗黙的nullで返されます。 コールバックは2つのパラメーターを取ります。

  • エラーエラー
    Lambda自体が失敗した場合のエラー情報を提供します。 Lambdaが成功した場合、 nullをこのパラメーターに渡す必要があります。
  • オブジェクトの結果
    応答オブジェクトを提供するため。 JSON.stringifyと互換性がある必要があります。 エラーフィールドにパラメータがある場合、このフィールドは無視されます。

静的サイトはイベント本文でフォームデータを送信し、コールバックはユーザーが確認できるように応答を返します。

serverless.ymlには、サービスの名前、プロバイダー情報、および関数が表示されます。

 # serverless.yml service: static-site-mailer provider: name: aws runtime: nodejs6.10 functions: hello: handler: handler.hello 
serverless.ymlの関数名がhandler.jsにどのようにマッピングされるか。
serverless.ymlの関数名がhandler.jsにどのようにマッピングされるか。

hello関数とハンドラーの間のマッピングに注意してください。 ファイルに名前を付けて機能させることができ、構成にマップされている限り、機能します。 関数の名前をstaticSiteMailerに変更しましょう。

 # serverless.yml functions: staticSiteMailer: handler: handler.staticSiteMailer
 // handler.js module.exports.staticSiteMailer = (event, context, callback) => { ... };

Lambda関数には、他のAWSインフラストラクチャとやり取りするためのパーミッションが必要です。 メールを送信する前に、SESに送信を許可する必要があります。 serverless.ymlのprovider.iamRoleStatementsの下に権限を追加します。

 # serverless.yml provider: name: aws runtime: nodejs6.10 iamRoleStatements: - Effect: "Allow" Action: - "ses:SendEmail" Resource: ["*"]

フォームアクションにはURLが必要なので、関数にHTTPイベントを追加する必要があります。 serverless.ymlでパスを作成し、メソッドをpostとして指定し、セキュリティのためにCORSをtrueに設定します。

 functions: staticSiteMailer: handler: handler.staticSiteMailer events: - http: method: post path: static-site-mailer cors: true

更新されたserverless.ymlファイルとhandler.jsファイルは次のようになります。

 # serverless.yml service: static-site-mailer provider: name: aws runtime: nodejs6.10 functions: staticSiteMailer: handler: handler.staticSiteMailer events: - http: method: post path: static-site-mailer cors: true provider: name: aws runtime: nodejs6.10 iamRoleStatements: - Effect: "Allow" Action: - "ses:SendEmail" Resource: ["*"]
 // handler.js 'use strict'; module.exports.staticSiteMailer = (event, context, callback) => { const response = { statusCode: 200, body: JSON.stringify({ message: 'Go Serverless v1.0! Your function executed successfully!', input: event, }), }; callback(null, response); };

サーバーレスアーキテクチャがセットアップされたので、デプロイしてテストしてみましょう。 単純なJSON応答が返されます。

 yarn sls deploy --verbose yarn sls invoke --function staticSiteMailer { "statusCode": 200, "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{}}" } 
まったく新しいサーバーレス関数を呼び出したときの応答。
まったく新しいサーバーレス関数を呼び出したときの応答。

HTMLフォームの作成

Lambda関数の入力とフォームの出力は一致する必要があるため、関数をビルドする前に、フォームをビルドしてその出力をキャプチャします。 名前、メール、メッセージの各フィールドでシンプルにしています。 サーバーレスアーキテクチャをデプロイしてURLを取得したら、フォームアクションを追加しますが、POSTリクエストになることがわかっているので、それを追加できます。フォームの最後に、表示するための段落タグを追加します。送信コールバックで更新するユーザーへの応答メッセージ。

 <form action="{{ SERVICE URL }}" method="POST"> <label> Name <input type="text" name="name" required> </label> <label> Email <input type="email" name="reply_to" required> </label> <label> Message: <textarea name="message" required></textarea> </label> <button type="submit">Send Message</button> </form> <p></p>

出力をキャプチャするには、送信ハンドラーをフォームに追加し、フォームパラメーターをオブジェクトに変換して、文字列化されたJSONをLambda関数に送信します。 Lambda関数では、 JSON.parse()を使用してデータを読み取ります。 または、jQueryのSerializeまたはquery-stringを使用して、フォームパラメーターをクエリ文字列として送信および解析できますが、 JSON.stringify()およびJSON.parse()はネイティブです。

 (() => { const form = document.querySelector('form'); const formResponse = document.querySelector('js-form-response'); form.onsubmit = e => { e.preventDefault(); // Prepare data to send const data = {}; const formElements = Array.from(form); formElements.map(input => (data[input.name] = input.value)); // Log what our lambda function will receive console.log(JSON.stringify(data)); }; })();

先に進み、フォームを送信してから、コンソール出力をキャプチャします。 次のLambda関数で使用します。

コンソールログにフォームデータをキャプチャします。
コンソールログにフォームデータをキャプチャします。

ラムダ関数の呼び出し

特に開発中は、関数が期待どおりに機能するかどうかをテストする必要があります。 Serverless Frameworkは、 invokeおよびinvoke localコマンドを提供して、それぞれライブ環境と開発環境から関数をトリガーします。 どちらのコマンドにも、渡された関数名(この場合はstaticSiteMailer )が必要です。

 yarn sls invoke local --function staticSiteMailer

模擬データを関数に渡すには、JSONオブジェクト内のbodyキーの下にキャプチャされたコンソール出力を使用してdata.jsonという名前の新しいファイルを作成します。 次のようになります。

 // data.json { "body": "{\"name\": \"Sender Name\",\"reply_to\": \"[email protected]\",\"message\": \"Sender message\"}" }

ローカルデータを使用して関数を呼び出すには、ファイルへのパスとともに--path引数を渡します。

 yarn sls invoke local --function staticSiteMailer --path data.json 
JSONデータを渡すときのサーバーレス関数からの更新された戻り応答。
JSONデータを渡すときのサーバーレス関数からの更新された戻り応答。

以前と同様の応答が表示されますが、 inputキーには、モックしたイベントが含まれます。 模擬データを使用して、Simple EmailServiceを使用してメールを送信しましょう。

シンプルなメールサービスでメールを送信

staticSiteMailer関数をプライベートsendEmail関数の呼び出しに置き換えます。 今のところ、テンプレートコードをコメントアウトまたは削除して、次のように置き換えることができます。

 // hander.js function sendEmail(formData, callback) { // Build the SES parameters // Send the email } module.exports.staticSiteMailer = (event, context, callback) => { const formData = JSON.parse(event.body); sendEmail(formData, function(err, data) { if (err) { console.log(err, err.stack); } else { console.log(data); } }); };

まず、 event.bodyを解析してフォームデータをキャプチャし、次にそれをプライベートsendEmail関数に渡します。 sendEmailは電子メールの送信を担当し、コールバック関数はerrまたはdataを含む失敗または成功の応答を返します。 この場合、エラーまたはデータをログに記録するだけで済みます。これは、すぐにLambdaコールバックに置き換えられるためです。

Amazonは、サービスをLambda関数に接続するための便利なSDK、 aws-sdkを提供しています。 SESを含む彼らのサービスの多くはその一部です。 これをyarn add aws-sdkを使用してプロジェクトに追加し、ハンドラーファイルの先頭にインポートします。

 // handler.js const AWS = require('aws-sdk'); const SES = new AWS.SES();

プライベートsendEmail関数では、解析されたフォームデータからSES.sendEmailパラメーターを作成し、コールバックを使用して呼び出し元に応答を返します。 パラメータには、オブジェクトとして次のものが必要です。

  • ソース
    SESが送信しているメールアドレス。
  • ReplyToAddresses
    電子メールのフィールドへの返信に追加された電子メールアドレスの配列。
  • 行き先
    少なくとも1つのToAddressesCcAddresses 、またはBccAddressesを含む必要があるオブジェクト。 各フィールドは、 tocc 、およびbccフィールドにそれぞれ対応する電子メールアドレスの配列を取ります。
  • メッセージ
    BodySubjectを含むオブジェクト。

formDataはオブジェクトであるため、 formData.messageのようにフォームフィールドを直接呼び出し、パラメータを作成して送信できます。 SESで確認したメールをSourceDestination.ToAddressesに渡します。 メールが確認されている限り、さまざまなメールアドレスを含め、ここで何でも渡すことができます。 reply_tomessageを取り出し、 formDataオブジェクトからnameを付けて、 ReplyToAddressesフィールドとMessage.Body.Text.Dataフィールドに入力します。

 // handler.js function sendEmail(formData, callback) { const emailParams = { Source: '[email protected]', // SES SENDING EMAIL ReplyToAddresses: [formData.reply_to], Destination: { ToAddresses: ['[email protected]'], // SES RECEIVING EMAIL }, Message: { Body: { Text: { Charset: 'UTF-8', Data: `${formData.message}\n\nName: ${formData.name}\nEmail: ${formData.reply_to}`, }, }, Subject: { Charset: 'UTF-8', Data: 'New message from your_site.com', }, }, }; SES.sendEmail(emailParams, callback); }

SES.sendEmailが電子メールを送信し、コールバックが応答を返します。 ローカル関数を呼び出すと、確認済みのアドレスにメールが送信されます。

 yarn sls invoke local --function staticSiteMailer --path data.json 
成功した場合のSES.sendEmailからの応答。
成功した場合のSES.sendEmailからの応答。

ハンドラーからの応答を返す

私たちの関数はコマンドラインを使用して電子メールを送信しますが、それはユーザーがそれを操作する方法ではありません。 AJAXフォーム送信への応答を返す必要があります。 失敗した場合は、適切なstatusCodeerr.messageを返す必要があります。 成功すると、 200 statusCodeで十分ですが、メーラーの応答も本文に返されます。 staticSiteMailerで、応答データを作成し、 sendEmailコールバック関数をLambdaコールバックに置き換えます。

 // handler.js module.exports.staticSiteMailer = (event, context, callback) => { const formData = JSON.parse(event.body); sendEmail(formData, function(err, data) { const response = { statusCode: err ? 500 : 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': 'https://your-domain.com', }, body: JSON.stringify({ message: err ? err.message : data, }), }; callback(null, response); }); };

Lambdaコールバックは、 SES.sendEmailから成功メッセージと失敗メッセージの両方を返すようになりました。 errが存在するかどうかをチェックして応答を作成し、応答が一貫しているようにします。 Lambdaコールバック関数自体は、エラー引数フィールドにnullを渡し、2番目に応答を渡します。 エラーを先に渡したいのですが、Lambda自体が失敗した場合、そのコールバックはエラー応答で暗黙的に呼び出されます。

headersで、 Access-Control-Allow-Originを独自のドメインに置き換える必要があります。 これにより、他のドメインがあなたのサービスを使用して、あなたの名前でAWSの請求書を積み上げる可能性を防ぐことができます! この記事では取り上げませんが、独自のドメインを使用するようにLambdaを設定することは可能です。 SSL / TLS証明書をAmazonにアップロードする必要があります。 Serverless Frameworkチームは、その方法について素晴らしいチュートリアルを作成しました。

ローカル関数を呼び出すと、電子メールが送信され、適切な応答が返されます。

 yarn sls invoke local --function staticSiteMailer --path data.json 
サーバーレス関数からの戻り応答。本文にSES.sendEmail戻り応答が含まれています。
サーバーレス関数からの戻り応答。本文にSES.sendEmail戻り応答が含まれています。

フォームからLambda関数を呼び出す

私たちのサービスは完了です! デプロイするには、 yarn sls deploy -vを実行します。 デプロイされると、 https://r4nd0mh45h.execute-api.us-east-1.amazonaws.com/dev/static-site-mailerのようなURLが取得され、フォームアクションに追加できます。 次に、AJAXリクエストを作成し、ユーザーにレスポンスを返します。

 (() => { const form = document.querySelector('form'); const formResponse = document.querySelector('js-form-response'); form.onsubmit = e => { e.preventDefault(); // Prepare data to send const data = {}; const formElements = Array.from(form); formElements.map(input => (data[input.name] = input.value)); // Log what our lambda function will receive console.log(JSON.stringify(data)); // Construct an HTTP request var xhr = new XMLHttpRequest(); xhr.open(form.method, form.action, true); xhr.setRequestHeader('Accept', 'application/json; charset=utf-8'); xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); // Send the collected data as JSON xhr.send(JSON.stringify(data)); // Callback function xhr.onloadend = response => { if (response.target.status === 200) { // The form submission was successful form.reset(); formResponse.innerHTML = 'Thanks for the message. I'll be in touch shortly.'; } else { // The form submission failed formResponse.innerHTML = 'Something went wrong'; console.error(JSON.parse(response.target.response).message); } }; }; })();

AJAXコールバックでは、 response.target.statusを使用してステータスコードを確認します。 200以外の場合は、ユーザーにエラーメッセージを表示できます。それ以外の場合は、メッセージが送信されたことをユーザーに通知します。 Lambdaは文字列化されたJSONを返すため、 JSON.parse(response.target.response).messageを使用して本文メッセージを解析できます。 エラーをログに記録すると特に便利です。

静的サイトから完全にフォームを送信できるはずです。

静的サイトフォーム。メッセージをLambdaエンドポイントに送信し、ユーザーに応答を返します。
静的サイトフォーム。メッセージをLambdaエンドポイントに送信し、ユーザーに応答を返します。

次のステップ

サーバーレスフレームワークとAWSを使用すると、静的に連絡先フォームを簡単に追加できます。 ハニーポットを使用したフォーム検証の追加、無効なフォームのAJAX呼び出しの防止、応答の場合のUXの改善など、コードには改善の余地がありますが、これで十分です。 これらの改善のいくつかは、私が作成した静的サイトメーラーリポジトリ内で確認できます。 サーバーレスを自分で試してみるきっかけになれば幸いです。