You can bypass Lambda entirely and have API Gateway talk directly to DynamoDB, and it’s faster and cheaper for simple CRUD operations.

Let’s see it in action. Imagine you have a DynamoDB table named users with a primary key userId (string). You want to allow clients to GET a user by their userId via an API.

First, set up your DynamoDB table.

{
  "TableName": "users",
  "AttributeDefinitions": [
    {
      "AttributeName": "userId",
      "AttributeType": "S"
    }
  ],
  "KeySchema": [
    {
      "AttributeName": "userId",
      "KeyType": "HASH"
    }
  ],
  "ProvisionedThroughput": {
    "ReadCapacityUnits": 5,
    "WriteCapacityUnits": 5
  }
}

Next, create an API Gateway REST API. Within that API, create a GET resource (e.g., /users/{userId}).

Now, for the magic: configure the GET method on this resource to integrate directly with DynamoDB.

  1. Method Request:

    • Under "Method Request," ensure the userId path parameter is defined. This is crucial for passing the ID from the URL to DynamoDB.
  2. Integration Request:

    • Integration Type: Select "AWS Service."
    • AWS Region: Choose the region where your DynamoDB table resides.
    • AWS Service: Select "DynamoDB."
    • HTTP Method: Choose "POST" (DynamoDB’s API for GetItem is a POST request).
    • Action Type: Select "Use x-amz-target header."
    • x-amz-target: Enter DynamoDB_20120810.GetItem. This tells API Gateway which DynamoDB operation to call.
    • Request Body Passthrough: Uncheck this. We’ll define a custom passthrough.
    • Request Transformation: This is where you map the incoming API request to the DynamoDB GetItem API call. You’ll use a Velocity Template Language (VTL) template.

    Here’s the VTL template for the GET /users/{userId} method:

    {
      "TableName": "users",
      "Key": {
        "userId": {
          "S": "$util.escapeJavaScript($input.params('userId'))"
        }
      }
    }
    
    • TableName: Your DynamoDB table name.
    • Key: This maps to the GetItem operation’s Key parameter.
    • userId: Matches the primary key attribute name in your DynamoDB table.
    • "S": Specifies the data type of the attribute as String.
    • $util.escapeJavaScript($input.params('userId')): This is the key part. $input.params('userId') extracts the userId from the path parameter you defined in the "Method Request." $util.escapeJavaScript() ensures that any special characters in the userId are properly escaped for JSON, preventing syntax errors.
  3. IAM Permissions:

    • API Gateway needs permission to call DynamoDB. You’ll need to create or update an IAM role for your API Gateway to assume. This role must have a policy that allows dynamodb:GetItem on your users table.

    Example IAM policy:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "dynamodb:GetItem"
                ],
                "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/users"
            }
        ]
    }
    

    (Replace us-east-1 and 123456789012 with your AWS region and account ID.)

  4. Method Response:

    • Configure the expected response from DynamoDB. For a successful GetItem, DynamoDB returns a JSON object containing the Item.
    • You’ll likely want to map this DynamoDB Item back to a cleaner response for your API clients. In the "Integration Response," you can use another VTL template to transform the DynamoDB output.

    Example VTL for mapping DynamoDB Item to a simpler response:

    #set($inputRoot = $input.path('$'))
    #set($output = {})
    #set($output = $inputRoot.Item)
    $util.toJson($output)
    

    This VTL takes the Item field from the DynamoDB response ($inputRoot.Item) and directly returns it. If you need to rename fields or select specific ones, you’d do more complex VTL here.

  5. Deploy:

    • Deploy your API to a stage (e.g., dev or prod).

Now, if you make a GET request to https://your-api-id.execute-api.your-region.amazonaws.com/dev/users/user123, API Gateway will:

  1. Extract user123 from the path.
  2. Construct a GetItem request for DynamoDB using the VTL template.
  3. Call the DynamoDB GetItem API with the constructed request.
  4. Receive the Item from DynamoDB.
  5. Transform the Item using the integration response VTL.
  6. Return the final JSON response to the client.

This direct integration avoids the overhead of invoking and executing a Lambda function, reducing latency and cost for simple data retrieval or manipulation tasks. The VTL mapping is the critical piece, allowing you to translate the generic API Gateway request/response model into the specific DynamoDB API’s expectations.

The one thing most people don’t realize is that API Gateway’s VTL can directly access and manipulate the binary payload from AWS services when certain content types are configured, allowing for direct file uploads/downloads to S3 or even manipulating encrypted data with KMS before it hits the backend service.

The next step you’ll likely encounter is handling errors gracefully, like when a userId doesn’t exist in DynamoDB.

Want structured learning?

Take the full Apigateway course →