Skip to content

Build a Serverless REST API with API Gateway and Lambda

Intermediate

Create a fully serverless REST API using AWS API Gateway and Lambda functions, backed by a DynamoDB table.

Overview

This project guides you through building a serverless REST API on AWS. You will create Lambda functions that handle CRUD operations, expose them via API Gateway, and persist data in DynamoDB — all without managing any servers.

What You Will Learn

Prerequisites

Architecture

Client → API Gateway (HTTP API) → Lambda Function → DynamoDB Table

Steps

1. Create the DynamoDB Table

  1. Navigate to DynamoDB in the AWS Console.
  2. Click Create table.
  3. Set Table name to Items.
  4. Set Partition key to id (String).
  5. Leave defaults and click Create table.

2. Create the Lambda Function

  1. Navigate to LambdaCreate function.
  2. Choose Author from scratch.
  3. Name: items-handler, Runtime: Node.js 20.x.
  4. Click Create function.
  5. Replace the default code with:
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
  DynamoDBDocumentClient,
  GetCommand,
  PutCommand,
  DeleteCommand,
  ScanCommand,
} from "@aws-sdk/lib-dynamodb";
import { randomUUID } from "crypto";

const client = DynamoDBDocumentClient.from(new DynamoDBClient({}));
const TABLE = "Items";

export const handler = async event => {
  const method = event.requestContext.http.method;
  const id = event.pathParameters?.id;

  if (method === "GET" && !id) {
    const { Items } = await client.send(new ScanCommand({ TableName: TABLE }));
    return { statusCode: 200, body: JSON.stringify(Items) };
  }

  if (method === "GET" && id) {
    const { Item } = await client.send(
      new GetCommand({ TableName: TABLE, Key: { id } })
    );
    return Item
      ? { statusCode: 200, body: JSON.stringify(Item) }
      : { statusCode: 404, body: "Not found" };
  }

  if (method === "POST") {
    const body = JSON.parse(event.body);
    const item = { id: randomUUID(), ...body };
    await client.send(new PutCommand({ TableName: TABLE, Item: item }));
    return { statusCode: 201, body: JSON.stringify(item) };
  }

  if (method === "DELETE" && id) {
    await client.send(new DeleteCommand({ TableName: TABLE, Key: { id } }));
    return { statusCode: 204, body: "" };
  }

  return { statusCode: 405, body: "Method not allowed" };
};

3. Attach an IAM Policy to Lambda

  1. Go to your Lambda function → ConfigurationPermissions.
  2. Click the execution role link to open IAM.
  3. Attach an inline policy granting DynamoDB access:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:DeleteItem",
        "dynamodb:Scan"
      ],
      "Resource": "arn:aws:dynamodb:*:*:table/Items"
    }
  ]
}

4. Create the API Gateway

  1. Navigate to API GatewayCreate APIHTTP API.
  2. Click Add integration, choose Lambda, select items-handler.
  3. Set API name to items-api.
  4. Add routes:
    • GET /itemsitems-handler
    • POST /itemsitems-handler
    • GET /items/{id}items-handler
    • DELETE /items/{id}items-handler
  5. Click Next through stages, then Create.

5. Test the API

Copy the Invoke URL from the API Gateway console and test:

BASE="https://your-api-id.execute-api.us-east-1.amazonaws.com"

# Create an item
curl -X POST "$BASE/items" \
  -H "Content-Type: application/json" \
  -d '{"name": "Widget", "price": 9.99}'

# List all items
curl "$BASE/items"

# Get a specific item
curl "$BASE/items/ITEM_ID"

# Delete an item
curl -X DELETE "$BASE/items/ITEM_ID"

Clean Up

Delete the API Gateway, Lambda function, and DynamoDB table to avoid charges.

Going Further