Skip to content
Codeloom
AWS

Building REST APIs with API Gateway

Build serverless REST APIs with AWS API Gateway — resources, methods, Lambda integration, authorization, throttling, and deployment stages.

·3 min read · By Codeloom
Intermediate 10 min read

What you'll learn

  • How API Gateway creates serverless HTTP APIs
  • REST API vs HTTP API — when to use which
  • Lambda proxy integration
  • Authorization, throttling, and CORS

Prerequisites

  • AWS Lambda basics
  • Understanding of REST API concepts

API Gateway is a fully managed service that creates, publishes, and manages REST APIs. Combined with Lambda, it gives you a serverless backend that scales automatically.

REST API vs HTTP API

AWS offers two types:

FeatureREST APIHTTP API
Cost$3.50/million$1.00/million
FeaturesFull (caching, WAF, usage plans)Basic
Latency~30ms overhead~10ms overhead
AuthIAM, Cognito, Lambda authorizersIAM, JWT

Use HTTP API for simple Lambda-backed APIs. Use REST API when you need caching, request validation, or API keys.

Creating a REST API with SAM

# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: app.handler
      Runtime: python3.12
      Events:
        GetUsers:
          Type: Api
          Properties:
            Path: /users
            Method: get
        CreateUser:
          Type: Api
          Properties:
            Path: /users
            Method: post
        GetUser:
          Type: Api
          Properties:
            Path: /users/{userId}
            Method: get

Lambda proxy integration

With proxy integration, API Gateway passes the full HTTP request to Lambda and expects a specific response format.

import json

def handler(event, context):
    method = event["httpMethod"]
    path = event["path"]
    path_params = event.get("pathParameters") or {}

    if method == "GET" and path == "/users":
        return response(200, {"users": get_all_users()})

    if method == "GET" and "userId" in path_params:
        user = get_user(path_params["userId"])
        if not user:
            return response(404, {"error": "User not found"})
        return response(200, user)

    if method == "POST" and path == "/users":
        body = json.loads(event.get("body") or "{}")
        user = create_user(body)
        return response(201, user)

    return response(404, {"error": "Not found"})


def response(status_code, body):
    return {
        "statusCode": status_code,
        "headers": {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*",
        },
        "body": json.dumps(body),
    }

CORS

Enable CORS for browser clients:

# SAM template
Globals:
  Api:
    Cors:
      AllowMethods: "'GET,POST,PUT,DELETE'"
      AllowHeaders: "'Content-Type,Authorization'"
      AllowOrigin: "'https://myapp.com'"

Or handle it in Lambda:

def 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",
            "Access-Control-Allow-Headers": "Content-Type,Authorization",
        },
        "body": json.dumps(body),
    }

Authorization

Cognito authorizer

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      Auth:
        DefaultAuthorizer: CognitoAuthorizer
        Authorizers:
          CognitoAuthorizer:
            UserPoolArn: !GetAtt UserPool.Arn

Lambda authorizer

def authorizer(event, context):
    token = event.get("authorizationToken", "")

    if validate_token(token):
        return generate_policy("user", "Allow", event["methodArn"])
    else:
        return generate_policy("user", "Deny", event["methodArn"])

def generate_policy(principal, effect, resource):
    return {
        "principalId": principal,
        "policyDocument": {
            "Version": "2012-10-17",
            "Statement": [{
                "Action": "execute-api:Invoke",
                "Effect": effect,
                "Resource": resource,
            }],
        },
    }

Request validation

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      Models:
        CreateUserModel:
          type: object
          required: [name, email]
          properties:
            name:
              type: string
            email:
              type: string
              format: email

Throttling

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      MethodSettings:
        - HttpMethod: '*'
          ResourcePath: '/*'
          ThrottlingBurstLimit: 100
          ThrottlingRateLimit: 50

Deployment stages

# Deploy to staging
sam deploy --stack-name my-api-staging --parameter-overrides Stage=staging

# Deploy to production
sam deploy --stack-name my-api-prod --parameter-overrides Stage=prod

Summary

API Gateway + Lambda gives you a serverless REST API that scales from zero to millions of requests. Use proxy integration for simplicity, Cognito or Lambda authorizers for security, and SAM templates for infrastructure as code. Start with HTTP API for cost efficiency and switch to REST API when you need advanced features.