静的サイトのサーバーレスお問い合わせフォームの作成
公開: 2022-03-10静的サイトジェネレーターは、WordPressのようなコンテンツ管理システム(CMS)の高速でシンプルな代替手段を提供します。 サーバーやデータベースのセットアップはなく、ビルドプロセスと単純なHTML、CSS、JavaScriptだけがあります。 残念ながら、サーバーがなければ、すぐに限界に達するのは簡単です。 たとえば、お問い合わせフォームを追加する場合です。
サーバーレスアーキテクチャの台頭により、静的サイトに連絡フォームを追加することが、CMSに切り替える理由である必要はなくなりました。 両方の長所を活かすことができます。連絡先フォーム用のサーバーレスバックエンドを備えた静的サイトです(保守する必要はありません)。 おそらく何よりも、ポートフォリオのようなトラフィックの少ないサイトでは、多くのサーバーレスプロバイダーの上限により、これらのサービスは完全に無料になります。
この記事では、サーバーレスフレームワーク上で独自の静的サイトメーラーを構築するためのAmazon Web Services(AWS)LambdaおよびSimple Email Service(SES)APIの基本を学習します。 フルサービスは、AJAXリクエストから送信されたフォームデータを受け取り、Lambdaエンドポイントに到達し、データを解析してSESパラメーターを構築し、メールアドレスを送信して、ユーザーに応答を返します。 デプロイを通じてサーバーレスを初めてセットアップする方法を説明します。 完了するまでに1時間もかからないので、始めましょう。
セットアップ
サーバーレステクノロジーの使用を開始するには、最小限の前提条件があります。 私たちの目的では、これはYarn、サーバーレスフレームワーク、およびAWSアカウントを備えた単なるノード環境です。
プロジェクトの設定
Yarnを使用して、ServerlessFrameworkをローカルディレクトリにインストールします。
- プロジェクトをホストするための新しいディレクトリを作成します。
- コマンドラインインターフェイスでディレクトリに移動します。
- このプロジェクトの
package.json
ファイルを作成するには、yarn init
を実行します。 -
yarn add serverless
を実行して、フレームワークをローカルにインストールします。 -
yarn serverless create --template aws-nodejs --name static-site-mailer
を実行して、ノードサービステンプレートを作成し、static-site-mailer
という名前を付けます。
プロジェクトはセットアップされていますが、AWSサービスをセットアップするまで何もできません。
アマゾンウェブサービスアカウント、クレデンシャル、およびシンプルなメールサービスの設定
Serverless Frameworkは、AWSクレデンシャルを設定するためのビデオウォークスルーを記録していますが、ここにも手順を示しました。
- AWSアカウントにサインアップするか、すでにアカウントをお持ちの場合はログインしてください。
- AWS検索バーで、「IAM」を検索します。
- IAMページで、サイドバーの[ユーザー]をクリックしてから、[ユーザーの追加]ボタンをクリックします。
- [ユーザーの追加]ページで、ユーザーに名前を付けます。「サーバーレス」などが適切です。 [アクセスの種類]で[プログラムによるアクセス]をオンにして、[次へ]をクリックします。
- アクセス許可画面で、[既存のポリシーを直接添付する]タブをクリックし、リストで[AdministratorAccess]を検索して確認し、[次へ]をクリックします。
- レビュー画面に、「プログラムによるアクセス」と「AdministratorAccess」の付いたユーザー名が表示されたら、ユーザーを作成します。
- 確認画面には、ユーザーの「アクセスキーID」と「シークレットアクセスキー」が表示されます。これらは、ServerlessFrameworkにアクセスを提供するために必要です。 CLIで、
yarn sls config credentials --provider aws --key YOUR_ACCESS_KEY_ID --secret YOUR_SECRET_ACCESS_KEY
と入力し、YOUR_ACCESS_KEY_ID
とYOUR_SECRET_ACCESS_KEY
を確認画面のキーに置き換えます。
これでクレデンシャルが設定されましたが、AWSコンソールでSimple EmailServiceを設定しましょう。
- 左上隅にある[コンソールホーム]をクリックして、ホームに戻ります。
- ホームページのAWS検索バーで、「SimpleEmailService」を検索します。
- SESホームページで、サイドバーの「メールアドレス」をクリックします。
- [メールアドレス]リストページで、[新しいメールアドレスを確認する]ボタンをクリックします。
- ダイアログウィンドウで、メールアドレスを入力し、[このメールアドレスを確認]をクリックします。
- アドレスを確認するためのリンクが記載されたメールがすぐに届きます。 リンクをクリックしてプロセスを完了します。
アカウントが作成されたので、サーバーレステンプレートファイルを見てみましょう。
サーバーレスフレームワークのセットアップ
serverless create
を実行すると、2つのファイルが作成されます。Lambda関数を含むhandler.jsと、サーバーレスアーキテクチャ全体の構成ファイルであるserverless.ymlです。 構成ファイル内で、必要な数のハンドラーを指定できます。各ハンドラーは、他の関数と対話できる新しい関数にマップされます。 このプロジェクトでは、単一のハンドラーのみを作成しますが、完全なサーバーレスアーキテクチャでは、サービスのさまざまな機能のいくつかを使用できます。
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
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
以前と同様の応答が表示されますが、 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つのToAddresses 、 CcAddresses 、またはBccAddressesを含む必要があるオブジェクト。 各フィールドは、 to 、 cc 、およびbccフィールドにそれぞれ対応する電子メールアドレスの配列を取ります。 - メッセージ
BodyとSubjectを含むオブジェクト。
formData
はオブジェクトであるため、 formData.message
のようにフォームフィールドを直接呼び出し、パラメータを作成して送信できます。 SESで確認したメールをSource
とDestination.ToAddresses
に渡します。 メールが確認されている限り、さまざまなメールアドレスを含め、ここで何でも渡すことができます。 reply_to
、 message
を取り出し、 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
ハンドラーからの応答を返す
私たちの関数はコマンドラインを使用して電子メールを送信しますが、それはユーザーがそれを操作する方法ではありません。 AJAXフォーム送信への応答を返す必要があります。 失敗した場合は、適切なstatusCode
とerr.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
フォームから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
を使用して本文メッセージを解析できます。 エラーをログに記録すると特に便利です。
静的サイトから完全にフォームを送信できるはずです。
次のステップ
サーバーレスフレームワークとAWSを使用すると、静的に連絡先フォームを簡単に追加できます。 ハニーポットを使用したフォーム検証の追加、無効なフォームのAJAX呼び出しの防止、応答の場合のUXの改善など、コードには改善の余地がありますが、これで十分です。 これらの改善のいくつかは、私が作成した静的サイトメーラーリポジトリ内で確認できます。 サーバーレスを自分で試してみるきっかけになれば幸いです。