Make a website dynamic using APIs

This is Part-2 of a multi-part blog post of how you can run a fast dynamic website in a completely serverless manner using managed services provided by AWS

In the previous post, we have discussed how to setup a static website using S3.

Every website has at least one dynamic section like contact us, email subscription or a feedback form. When hosting the website using serverless technologies such as Amazon S3, APIs are essential for powering the dynamic sections of the website. Amazon API Gateway gives us the ability to create any number of arbitrary APIs using Amazon Lambda as the backend. The best thing about these two services is, their Free Tier quota is quite high so you won’t have to pay anything until your website gets very popular.

Lets create a contact-us api for a website. First we need a data store to keep our contact-us form data, and for that we will use Amazon DynamoDB (NoSQL Database). Then we need an Amazon Lambda function to process the POST requests of the contact-us form. And finally we need an API endpoint to call the Lambda function from the website for that we will use Amazon API Gateway.

DynamoDB Table Creation

Logon on AWS Management console and select DynamoDB and follow these steps.

  1. Click Create table.
  2. Enter mywebsite-contact-us as Table name.
  3. Enter email as Partition key.
  4. Leave the rest of the settings as it is and click Create.

Note: Table creation may take few minutes.

Once the table is ready, lets write a Lambda function in Node.js to store contact-us form data into this table.

Lambda Function Creation

Logon on AWS Management console and select Lambda and follow below steps.

  1. Click Create a Lambda function.
  2. Select Blank function.
  3. Skip Configure Triggers and click Next.
  4. In Configure function, set mywebsite-contact-us as Name and select Nodejs 4.3 as Runtime.
  5. Copy below function to Lambda function code.

    'use strict';
    
    const AWS = require("aws-sdk");
    
    const dynamo = new AWS.DynamoDB.DocumentClient();
    
    exports.handler = (event, context, callback) => {
       const contactInfo = {};
       contactInfo.Item = {
         "email": event.email,
         "name": event.name,
         "message": event.message
       };
       contactInfo.TableName = "mywebsite-contact-us";
       dynamo.put(contactInfo, callback);
    };
    
  6. Select Create a custom role as Role.
  7. Set mywebsite_lambda_role as Role Name and Click Allow.
  8. Click Next and then Create function.

Lambda function Permissions

The Lambda function needs permissions to store data in the DynamoDB table mywebsite-contact-us. Logon on to the AWS Management console and select IAM and follow these steps to set required permissions.

  1. Click on Roles and select mywebsite_lambda_role.
  2. Under Inline Polices select Create Role Policy.
  3. Select Custom Policy and enter mywebsite-contact-us-table as Policy name.
  4. Copy and paste the following policy.
    {
       "Version": "2012-10-17",
       "Statement": [
           {
               "Sid": "mywebsiteContactUsTableWrite",
               "Effect": "Allow",
               "Action": [
                   "dynamodb:PutItem",
                   "dynamodb:UpdateItem"
               ],
               "Resource": [
                   "arn:aws:dynamodb:*:*:table/mywebsite-contact-us"
               ]
           }
       ]
    }
    

Now that the Lambda function has right permissions to write to the mywebsite-contact-us DynamoDB table, lets create an API end point for this Lambda function using API Gateway.

API Creation

Logon on to the AWS Management console and select API Gateway and follow these steps.

  1. Click “Getting started”.
  2. Click “Create API”.
  3. Select check box “Import from Swagger”
  4. Paste following swagger template and then click “Import”
    {
     "swagger": "2.0",
     "info": {
       "title": "mywebsite"
     },
     "paths": {
       "/contact-us": {
         "post": {
           "produces": [
             "application/json"
           ],
           "responses": {
             "200": {
               "description": "200 response",
               "schema": {
                 "$ref": "#/definitions/Empty"
               },
               "headers": {
                 "Access-Control-Allow-Origin": {
                   "type": "string"
                 }
               }
             }
           }
         },
         "options": {
           "consumes": [
             "application/json"
           ],
           "produces": [
             "application/json"
           ],
           "responses": {
             "200": {
               "description": "200 response",
               "schema": {
                 "$ref": "#/definitions/Empty"
               },
               "headers": {
                 "Access-Control-Allow-Origin": {
                   "type": "string"
                 },
                 "Access-Control-Allow-Methods": {
                   "type": "string"
                 },
                 "Access-Control-Allow-Headers": {
                   "type": "string"
                 }
               }
             }
           }
         }
       }
     },
     "definitions": {
       "Empty": {
         "type": "object",
         "title": "Empty Schema"
       }
     }
    }
    

The mywebsite API is created with contact-us resource and we will now have to integrate it with the Lambda function mywebsite-contact-us to process contact-us form requests from your website.

API Gateway and Lambda integration

  1. Select mywebsite API.
  2. Click on POST method under contact-us resource.
  3. For Integration type select Lambda function.
  4. Select the region of mywebsite-contact-us Lambda function.
  5. Set Lambda function as mywebsite-contact-us and click Save.
  6. Click OK to give permisison for API Gateway to call mywebsite-contact-us Lambda function.
  7. Click on OPTIONS method under contact-us resource.
  8. For Integration type select Mock and click Save.
  9. Click Enable CORS under Actions for Cross-Origin Resource Sharing. This is needed for posting contact-us form data to this API from your website.

The mywebsite API is created now and we need to deploy it so that we can make calls to the API.

Deploy the API

  1. Select Deploy API under Actions.
  2. Select New Stage and Set test as stage.
  3. Keep Invoke URL handy as we will need this for testing.

Now everything is ready and we need to make sure everything is working as expected.

Test the API

  1. We use Postman for API testing but feel free to use any REST client.
  2. Our testing URL will be Invoke URL appended with contact-us, for example the testing URL should look like https://abcde12345.execute-api.ap-southeast-1.amazonaws.com/test/contact-us.
  3. Select method as POST and use the testing URL.
  4. Post following JSON as request body.
    {
     "email": "info@tensult.com", 
     "name": "Dilip",
     "message": "I am just testing :)"
    }
    
  5. Logon on to the AWS Management Console, and navigate to DynamoDB. Here check the items of the table mywebsite-contact-us and you should find one entry with the above details.

Architecture for Contact us request flow

We have covered only few aspects the website here and there is lot to cover so in upcoming posts, so watch out for future posts in this series.

Read more.