Open In App

Building a Serverless Blog with AWS Lambda and API Gateway

Last Updated : 17 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

AWS Lambda is a serverless computing service offered by AWS. It enables you to run code in response to events without the need to manage servers. This event-driven service charges you based on actual compute time, making it cost-effective. Lambda supports various programming languages, scales automatically, and seamlessly integrates with other AWS services, making it an ideal choice for building dynamic applications with minimal operational overhead.

Amazon API Gateway

Amazon API Gateway works hand-in-hand with AWS Lambda. It makes it easy to create and manage APIs, acting as a bridge between applications and backend services. It ensures security through authentication and authorization and keeps an eye on how the API is used. Plus, it protects against misuse with features like rate limits. This service is crucial for building safe and scalable APIs that connect different parts of a system smoothly. When combined with AWS Lambda, it’s a powerful duo for creating dynamic, event-driven applications.

In order to perform these operations, we have to write our backend logic. We will create a Lambda Function for that. Then we build a Blog API using AWS API Gateway and integrate that with our lambda function. When a user invokes our Blog API, API Gateway routes the request to our Lambda function. The Lambda function interacts with DynamoDB and returns a response to API Gateway. API Gateway then returns a response to the end user.

AWS API Cloud Architecture

Create a DynamoDB Table

DynamoDB is a powerful, fully managed AWS NoSQL database service offered by AWS. It’s designed for high performance and easy scalability. Unlike traditional databases, it doesn’t require predefined table structures. It ensures fast access to data, offers features like backups and fine-grained access control, and is cost-effective.

Steps To Create A Table

  • Login your AWS account and go to DynamoDB service. Click upon the “Create Table” button to create a table “blog-database”.
  • For partition key, enter “blogId”.Table
  • DynamoDB also offers a new option regarding the provisioning of read & write capacities: The On-demand mode. Select the Table Settings as Customised Settings and then in Read Write capacity settings, select the capacity mode “On-demand”.Read Write Operations
    • This mode is great if you have no idea about how much read and write capacity you will need. And you can of course always switch back to fixed limits, too. If you do know which limits make most sense for you, the traditional “in-advance” provisioning will be cheaper.
  • Click on the “Create Table” button at the end. Now, you can see your created table in the Tables tab.blog-database table created

Create a Lambda Function

Now, we will create a lambda function for the backend of our API. The lambda function need to handle the operations for creating, reading, updating and deleting items in DynamoDB.

Steps to create a Lambda Function

  • Login your AWS account and go to Lambda Service. Click upon the “Create Function” button to create a lambda function.
  • Select “Author from scratch” and write the function name as “blog-api-lambda” and go with the default settings and hit “Create Function” at the end.Configurations Of AWS lambda functions
  • Now in the Code Source, you can see a file “index.mjs”. Rename it as “index.js”. Test the code
  • Go to the runtime settings and change the runtime to “Node.js 14.x” and save.Runtime Settings
  • Now replace the contents of index.js with the following code and deploy API.

    Node

    const AWS = require("aws-sdk");
    const dynamoDB = new AWS.DynamoDB.DocumentClient({
    region: ‘us-east-1’,
    apiVersion: ‘2012-08-10’,
    });

    exports.handler = async (event, context, callback)=>{
    if(event.id === undefined){
    if(event.httpMethod === "GET"){ // retrieve all blogs from database
    const params = {
    TableName: "blog-database"
    }
    await dynamoDB.scan(params).promise().then((data)=>{
    const restructuredData = data.Items.map((newData)=>{
    return ({"blogId": newData.blogId, "title": newData.title, "content": newData.content, "author": newData.author});
    });
    callback(null, restructuredData);
    }).catch((err)=>{
    callback(err);
    })
    }
    else if(event.httpMethod === "POST"){ // create a blog in the database
    const params = {
    Item: {
    blogId: "blog_"+Math.random(),
    title: event.title,
    content: event.content,
    author: event.author
    },
    TableName: "blog-database"
    }
    await dynamoDB.put(params).promise().then((data)=>{
    callback(null, data);
    }).catch((err)=>{
    callback(err);
    })
    }
    else{
    callback(null, `Method: ‘${event.httpMethod}’ is not allowed`);
    }
    }
    else{
    if(event.httpMethod === "GET"){ // retrieve a particular blog from database
    const params = {
    Key: {
    blogId: event.id
    },
    TableName: "blog-database"
    }
    await dynamoDB.get(params).promise().then((data)=>{
    const restructuredData = {
    "blogId": data.Item.blogId,
    "title": data.Item.title,
    "content": data.Item.content,
    "author": data.Item.author
    }
    callback(null, restructuredData);
    }).catch((err)=>{
    callback(err);
    })
    }
    else if(event.httpMethod === "PATCH"){ // updade a particular blog in database
    const params = {
    Key: {
    blogId: event.id
    },
    UpdateExpression: `set ${event.key} = :value`,
    ExpressionAttributeValues: {
    ":value": event.value
    },
    TableName: "blog-database",
    ReturnValues: "UPDATED_NEW"
    };

    await dynamoDB.update(params).promise().then((data)=>{
    callback(null, data);
    }).catch((err)=>{
    callback(err);
    })

    }
    else if(event.httpMethod === "DELETE"){ // delete a particular blog from database
    const params = {
    Key: {
    blogId: event.id
    },
    TableName: "blog-database"
    }
    await dynamoDB.delete(params).promise().then((data)=>{
    callback(null, data);
    }).catch((err)=>{
    callback(err);
    })
    }
    else{
    callback(null, `Method: ‘${event.httpMethod}’ is not allowed`);
    }
    }
    }

    • Your Lambda function is ready to be used. But, by default, no service has any permissions. So, we have to provide this lambda function some permissions to read/write access to DynamoDB. So, go to IAM console and go to Roles section. You can see some roles related to lambda function name. Open the role for your lambda function.
    • There you can find Attach Policies button inside Add Permissions. Click there and add the “AmazonDynamoDBFullAccess” policy.PermissionsAmazonDynamoDBFullAccess Policy
    • Now, lambda function is ready to access DynamoDB.

    Setup API Gateway

    Now, we will create our Blog-API. We will use the API Gateway service. Let’s understand what we are gonna create, what will happen behind the scenes of the API —

    • We will create an API that will have the following routes:
      • /blogs POST to create a blog, GET to fetch all blogs
      • /blogs/:id GET to fetch a particular blog
      • /blogs/:id PATCH to update a particular blog
      • /blogs/:id DELETE to delete a particular blog

    Our backend logic (lambda) is created earlier. So, we just have to create these API routes and connect those with our lambda function.

    To achieve this, follow the steps below —

    Login your AWS account and go to API Gateway Service. Click upon the “Create API” button and choose REST API (not Private) and click upon the “build” button to create a AWS REST API.

    You can see 3 types of API Endpoints —

    Regional: It is intended for the clients in the same region. When clients are running in the same regions i.e. API is intended to serve a small number of clients with high demands, Regional API reduces connection overhead.

    Edge Optimized: It is best for geographically distributed clients. API requests are routed to the nearest CloudFront Point of Presence(POP).

    Private: It is an API endpoint that can only be accessed from my Amazon Virtual Private Cloud (VPC).

    Let’s create an API of Regional Endpoint. Now our API is created. We just have to define all the HTTP methods our API will react to and all the resources our API will use.Choose the protocol

    Now create a resource providing resource name & resource path. Here, we are creating a resource with name “blogs” and path “blogs”.

    New Child Resources

    blogs resource

    • Now we have to define the methods (GET, POST etc) we want to handle. So, click on “Create Method” and select the method you want to define. I am selecting GET to retrieve all blogs. Now there are some API Integration Types (which kind of action you want to execute whenever a request hits this resource). We will select Lambda Function and from all the lambda functions, we have to choose that lambda function we created earlier i.e. “blog-api-lambda”. Now, save it.
      Get Call

      GET request setup in blogs resource

    Now, inside the Integration Request, go to Mapping Template and check “When there are no template defined(recommended)” and create a mapping template with “application/json‘ and generate template using “Method Request Passthrough”. You can replace all commands with the following code & save the code. Yeah! GET request on /blogs route will now be handled by our lambda function.

    XML




    {
        "httpMethod": "$context.httpMethod"
    }

    
    

    • Similarly, create the following API Resources and Methods —
      • POST in /blogs: This is same as previous, just at the body template, use the following code:

    XML




    #set($inputRoot = $input.path('$'))
    {
      "httpMethod": "$context.httpMethod",
      "title" : "$inputRoot.title",
      "content" : "$inputRoot.content",
      "author" : "$inputRoot.author"
    }

    
    

    • GET in /blogs/{id}: For these type of request handling, we need to create a new Dynamic Resource with parameter id. So, create a dynamic resource providing resource name & resource path as id and {id} respectively. Now, your dynamic resource is created. Just handle the GET request same as previous. Just, in mapping template use the following code:

      XML




      {
          "httpMethod": "$context.httpMethod",
          "id" : "$input.params().path.id"
      }

      
      

      • PATCH in /blogs/{id}: Create a PATCH method to handle the update blogs query using PATCH method in /blogs/{id} route which is same as previous. Just use the following code in the mapping template:

      XML




      #set($inputRoot = $input.path('$'))
      {
          "id" : "$input.params().path.id",
          "httpMethod": "$context.httpMethod",
          "key" : "$inputRoot.key",
          "value" : "$inputRoot.value"
      }

      
      

      • DELETE in /blogs/{id}: Create a DELETE method to handle the delete blogs query using DELETE method in /blogs/{id} route which is same as previous. Just use the following code in the mapping template —

      XML




      {
          "id" : "$input.params().path.id",
          "httpMethod": "$context.httpMethod"
      }

      
      

      • Finally, all the resources & methods will look like the image given below. We just need to deploy our API now. Just click upon the “Deploy API” button. Fill the stage name, description as given below and click on “Deploy”.Deploy API
      • Congrats!! Your blog-api is now live.

      Testing our Blog API

      • Make a POST request on /blogs route with the following JSON:
        • { “title”: “Deploy your React Application on AWS”, “content”: “This is the content for my first blog”, “author”: “Arindam Halder”}

        Creating Blogs

      • Make a GET request on /blogs route, you can see all blogsReading all Blogs

      • Make a GET request on /blogs/{id} route, you can see the particular blog.Reading a particular blog

      • Make a PATCH request on /blogs/{id} route with the following JSON:
        • {“key”: “author”, “value”: “arindam369”}

        Updating a particular BlogModified Blog Data

      • Make a DELETE request on /blogs/{id} route, the blog will be deletedDeleting a Particular Blog

      FAQs On Building a Serverless Blog with AWS Lambda and API Gateway

      1. Why Use AWS Lambda And API Gateway For Building A Serverless Blog?

      AWS Lambda and API Gateway are serverless computing services provided by Amazon Web Services (AWS). They enable you to run code in response to events and create APIs without the need to manage servers. This approach reduces operational overhead, scales automatically, and allows you to pay only for the resources you consume.

      2. Can I Handle User Authentication And Authorization In a Serverless Blog?

      Yes, You can use AWS Cognito, a service that provides authentication, authorization, and user management. It integrates seamlessly with AWS Lambda and API Gateway, allowing you to secure your endpoints and manage user accounts.



      Like Article
      Suggest improvement
      Share your thoughts in the comments

      Similar Reads