Building REST APIs with API Gateway
Build serverless REST APIs with AWS API Gateway — resources, methods, Lambda integration, authorization, throttling, and deployment stages.
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:
| Feature | REST API | HTTP API |
|---|---|---|
| Cost | $3.50/million | $1.00/million |
| Features | Full (caching, WAF, usage plans) | Basic |
| Latency | ~30ms overhead | ~10ms overhead |
| Auth | IAM, Cognito, Lambda authorizers | IAM, 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.
Related articles
- AWS Deploying to ECS Fargate
Deploy containerized apps to AWS ECS Fargate — task definitions, services, load balancers, auto-scaling, and CI/CD deployment.
- AWS AWS Lambda with Python: A Practical Guide
Build serverless functions with AWS Lambda and Python — handlers, events, layers, environment variables, API Gateway integration, and best practices.
- AWS S3 Operations with Boto3
Master S3 operations in Python — upload, download, presigned URLs, multipart uploads, lifecycle policies, and event notifications.
- AWS AWS API Gateway vs ALB: Choosing the Right Entry Point
Compare API Gateway and Application Load Balancer for fronting AWS workloads, including features, pricing, latency, and when to use each in production.