Implementing a Website Feedback Form Using Amazon API Gateway, SNS, and AWS Lambda

Diagram showing an API Gateway endpoint that receives an HTTP POST request and forwards it to a Lambda function, which, in turn, publishes it to an SNS Topic.

Last updated: August 25, 2019

Customer feedback is vital for running a successful business. In most cases, customers do not spend time for opening an email client and sending a message to the contact email address. That is why most websites offer some type of “Contact Us” or “Feedback” form.

Static websites do not run any server-side code. In this case, you need to use an external service to allow the submission of customer feedback on your website. There are plenty of free or low-cost third party services on the market. Even for a dynamic website, you may decide to use one of them.

If you need more control over this feature, but still expect ease of configuration and low cost, you may decide to use an Amazon API Gateway endpoint. API Gateway handles all necessary tasks, including rate limiting, authorization, and access control.

This blog post describes how to create a simple API Gateway endpoint and integrate it with the feedback page of your website.

How to Create a Serverless Feedback Form for a Static Website Using Amazon API Gateway, SNS, and AWS Lambda

In this procedure, you use a CloudFormation template to create an Amazon API Gateway endpoint, an AWS Lambda function, and an SNS topic.

  • In the simplest case, you can use the API Gateway API with AWS integration to expose your API directly to the Amazon SNS service. However, in this procedure, you additionally use a Lambda function because you can implement in this function your custom logic, for example, Google reCAPTCHA validation.

When a customer submits feedback on your website, an HTTP POST request is sent to the API Gateway endpoint. Then, the corresponding API Gateway method invokes the Lambda function. The customer name, email, and message are passed as a payload to the Lambda function. The Lambda function publishes the payload to the SNS topic that delivers it to the configured email subscription.

Flow diagram showing an HTML form. When the submit button is pressed, an HTTP POST request is sent to the API Gateway endpoint. Then, the corresponding API Gateway method invokes the Lambda function. The Lambda function publishes the payload to the Amazon SNS topic that delivers it to the website owner.

For the source code of the used Lambda function, see Appendix B, Lambda Function That Validates and Publishes Feedback to an SNS Topic (Python).

To create a website feedback form, perform the following steps:

  1. Open the CloudFormation Management Console at https://console.aws.amazon.com/cloudformation/home and switch to the AWS region where you want to create the Amazon API Gateway endpoint, AWS Lambda function, and SNS topic. Then, use the following CloudFormation template to create a new stack with all the required resources. The download URL of the website-feedback-form.json CloudFormation template.
    • In the parameters of the stack, you have to provide your valid email address. For the rest configuration parameters, you can accept the default values.
  2. Open the email message from AWS Notifications that you received on the configured email address and click the confirmation link.
  3. Send a test request to the API Gateway endpoint.
    Get the <API Gateway Invoke URL> value from the outputs of the created CloudFormation stack. Then, execute the following command:
    curl -i -X POST '<API Gateway Invoke URL>' \
    -H 'Content-Type: application/json' \
    --data '{"name": "John Doe", "email": "john.doe@example.com", "message": "Dummy"}'
    
    The test is successful if the returned HTTP status code is 200 (OK), and dummy feedback is delivered to your email address.
  4. Integrate the feedback form of your website with your API Gateway endpoint.
    For example, you can use the HTML form (Bootstrap), and the corresponding JavaScript block (jQuery) from Appendix A, Feedback HTML Form (Bootstrap).

Appendix A, Feedback HTML Form (Bootstrap)

The following HTML and JavaScript code snippets show how you can integrate the feedback page of your website with your API Gateway endpoint. In these examples, you use the Bootstrap framework and jQuery JavaScript library.

<!-- CloudBriefly.com --> 

<link rel="stylesheet"
 href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">

<form id="feedback-form" method="POST">
    <h3>Feedback</h3>
    <div class="form-group">
        <label for="name">Name</label>
        <input id="name" type="text" class="form-control" name="name">
    </div>
    <div class="form-group">
        <label for="email">E-mail address</label>
        <input id="email" type="email" class="form-control" name="email">
    </div>
    <div class="form-group">
        <label for="message">Message</label>
        <textarea id="message" class="form-control" name="message" required></textarea>
    </div>
    <button type="submit" class="btn btn-primary">
        <span>Submit</span>
    </button>
</form>

In the following JavaScript code, replace <API Gateway Invoke URL> with the actual URL of your API Gateway endpoint.

// CloudBriefly.com

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<script>
    $(document).ready(function(){
        $("#feedback-form>button[type=submit]").click(function(e){
            e.preventDefault();

            var apiGatewayInvokeURL = '<API Gateway Invoke URL>';
            var body = {name : $("#name").val(), email : $("#email").val(), 
                        message: $("#message").val()};

            $.ajax({
                type: 'POST',
                url : apiGatewayInvokeURL,
                dataType: 'json',
                crossDomain: 'true',
                contentType: 'application/json; charset=utf-8',
                data: JSON.stringify(body),

                success: function () {
                    $("#feedback-form").trigger('reset');
                    alert('Success');
                },
                error: function (response) {
                    alert('Failed: HTTP ' + response.status);
                }
            });
        });
    });
</script>

Appendix B, Lambda Function That Validates and Publishes Feedback to an SNS Topic (Python)

The following Python code snippet shows how you can publish customer feedback to an SNS topic when the Lambda proxy integration (AWS_PROXY) is used in the API Gateway configuration. The code is compatible with Python 2.7, Python 3.6 and Python 3.7.

In the following Python code, replace feedback-topic with the actual name of your SNS topic.

# CloudBriefly.com

from __future__ import print_function
import json
import boto3

def lambda_handler(event, context):
    topic_name = 'feedback-topic'
    aws_region = context.invoked_function_arn.split(':')[3]
    aws_account_id = context.invoked_function_arn.split(':')[4]
    body = json.loads(event['body'])  # Customer feedback

    response = {'headers': {'Access-Control-Allow-Origin': '*'}}  # Enable CORS

    # Basic validation
    # Long strings are truncated to 4096 characters
    for key in ['name', 'email', 'message']:
        body[key] = '-' if key not in body or not bool(body[key].strip()) \
                        else body[key].strip()[:4096]

    # TODO: custom validation checks

    notification = '%s [%s]:\n%s\n' % (body['name'], body['email'], body['message'])

    # Publish to Amazon SNS
    try:
        sns_client = boto3.client('sns')
        sns_response = sns_client.publish(
            TopicArn='arn:aws:sns:%s:%s:%s' % (aws_region, aws_account_id, topic_name),
            Subject='New feedback', Message=notification
        )
        response['statusCode'] = sns_response['ResponseMetadata']['HTTPStatusCode']
        response['body'] = '{"message": "Success"}'
    except Exception as e:
        print(e)
        response['statusCode'] = 500

    return response