API Gateway + Lambda — Build Serverless REST APIs

Why API Gateway + Lambda Matters

Together, API Gateway and Lambda form the backbone of serverless API architectures. API Gateway handles HTTP routing, authentication, rate limiting, and request validation. Lambda executes your business logic. This combination replaces traditional web servers with a fully managed, auto-scaling API platform.

Why this matters for your career:

  • API Gateway + Lambda is the standard pattern for serverless APIs on AWS
  • Replaces traditional server management with auto-scaling infrastructure
  • Pay-per-request pricing means zero cost when APIs are idle
  • Serverless API design is a core AWS certification topic

Architecture Overview

Client (Browser/App)
       ↓ HTTP Request
API Gateway (REST/HTTP API)
       ↓ Event (JSON)
Lambda Function
       ↓ Query/Write
Database (DynamoDB, RDS, etc.)
       ↑ Response (JSON)
API Gateway
       ↑ HTTP Response
Client

Creating an API Gateway + Lambda API

Step 1: Create Lambda Function

import json
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')

def lambda_handler(event, context):
    http_method = event['httpMethod']
    path = event['path']
    body = json.loads(event.get('body', '{}'))

    if http_method == 'GET' and path == '/users':
        # List all users
        response = table.scan()
        return json_response(200, {'users': response['Items']})

    elif http_method == 'POST' and path == '/users':
        # Create a user
        user_id = body.get('id')
        name = body.get('name')
        table.put_item(Item={'id': user_id, 'name': name})
        return json_response(201, {'message': 'User created', 'id': user_id})

    elif http_method == 'GET' and path.startswith('/users/'):
        # Get user by ID
        user_id = path.split('/')[-1]
        response = table.get_item(Key={'id': user_id})
        if 'Item' in response:
            return json_response(200, response['Item'])
        return json_response(404, {'error': 'User not found'})

    elif http_method == 'PUT' and path.startswith('/users/'):
        # Update user
        user_id = path.split('/')[-1]
        table.update_item(
            Key={'id': user_id},
            UpdateExpression='SET #n = :name',
            ExpressionAttributeNames={'#n': 'name'},
            ExpressionAttributeValues={':name': body.get('name')}
        )
        return json_response(200, {'message': 'User updated'})

    elif http_method == 'DELETE' and path.startswith('/users/'):
        # Delete user
        user_id = path.split('/')[-1]
        table.delete_item(Key={'id': user_id})
        return json_response(200, {'message': 'User deleted'})

    return json_response(400, {'error': 'Invalid request'})


def json_response(status_code, body):
    return {
        'statusCode': status_code,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS',
            'Access-Control-Allow-Headers': 'Content-Type,Authorization'
        },
        'body': json.dumps(body)
    }

Step 2: Create API Gateway (REST API)

# Via AWS CLI
aws apigateway create-rest-api --name "Users API" --region us-east-1

# Get the API ID
api_id=$(aws apigateway get-rest-apis --query "items[?name=='Users API'].id" --output text)

# Get the root resource ID
root_id=$(aws apigateway get-resources --rest-api-id $api_id --query "items[0].id" --output text)

# Create /users resource
users_id=$(aws apigateway create-resource --rest-api-id $api_id --parent-id $root_id --path-part "users" --query "id" --output text)

# Create {id} sub-resource
id_param_id=$(aws apigateway create-resource --rest-api-id $api_id --parent-id $users_id --path-part "{id}" --query "id" --output text)

# Deploy the API
aws apigateway create-deployment --rest-api-id $api_id --stage-name prod

Step 3: Connect API Gateway to Lambda

# Give API Gateway permission to invoke Lambda
aws lambda add-permission \
  --function-name users-api \
  --statement-id api-gateway-invoke \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:us-east-1:123456789012:$api_id/*/*/users"

API Gateway Types

| Feature | REST API | HTTP API | WebSocket API | |---------|----------|----------|--------------| | Latency | Low | Very low (50% faster) | Low | | Price | Standard | ~70% cheaper | Standard | | Features | Full (WAF, API keys, usage plans, caching) | Limited (basic routing, JWT auth, CORS) | Real-time, bidirectional | | Use case | Enterprise, complex APIs | Simple, cost-sensitive APIs | Chat, notifications, streaming |

CORS Configuration

// API Gateway response headers
{
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type,Authorization,X-Amz-Date,X-Api-Key",
  "Access-Control-Max-Age": "86400"
}

Authentication Options

| Method | Description | Complexity | |--------|-------------|------------| | API Keys | Simple key in header | Low | | IAM Authorization | AWS IAM roles and policies | Medium | | Cognito User Pools | User management with JWT | Medium | | Lambda Authorizer (Custom) | Custom auth logic | High | | JWT Authorizer (HTTP API) | Validate JWT from any provider | Low |

Best Practices

| Practice | Reason | |----------|--------| | Use HTTP API for simple APIs | 70% cheaper, lower latency | | Enable API caching | Reduce Lambda invocations, faster responses | | Set usage plans and API keys | Protect against abuse | | Enable request validation | Reject invalid requests before reaching Lambda | | Use CloudWatch logging | Debug and monitor API usage | | Enable throttling | Limit requests per second per client | | Use stage variables | Different configs for dev/staging/prod |

Summary

API Gateway + Lambda creates a fully managed, auto-scaling REST API without any servers. API Gateway handles HTTP routing, authentication, and throttling. Lambda executes your business logic. This pattern is the foundation of serverless architectures on AWS.

Key takeaways:

  • API Gateway routes HTTP requests to Lambda functions
  • REST API: full features, higher cost — HTTP API: simpler, lower cost
  • WebSocket API: real-time bidirectional communication
  • Implement CORS headers for browser-based API calls
  • Authentication options: API Keys, IAM, Cognito, Lambda Authorizer, JWT
  • Enable caching, throttling, and request validation for production
  • Use stage variables for environment-specific configuration

What's Next: DynamoDB

The next chapter covers DynamoDB — AWS's NoSQL database for serverless applications — tables, items, queries, scans, and integration with Lambda.

Request/Response Flow

When a client sends an HTTP request:

  1. API Gateway receives the request and matches it to a route
  2. API Gateway validates headers, query params, and body against the defined schema
  3. API Gateway transforms the request into a Lambda event JSON
  4. Lambda executes the handler with the event
  5. Lambda returns a response JSON
  6. API Gateway transforms the response into an HTTP response
  7. Client receives the HTTP response

Understanding this flow is critical for debugging serverless APIs and optimizing performance.

Member Exclusive Free Tutorial

This chapter is free exclusive content for registered members! Please login or register to unlock immediately.

Login / Register Now