API Gateway
APIs are the backbone of modern applications, enabling communication between services, mobile apps, and web frontends. Amazon API Gateway lets you create, publish, and manage APIs at any scale without managing servers. In this lesson, we'll explore how to build serverless APIs with API Gateway.
What You'll Learn
By the end of this lesson, you'll understand API Gateway concepts, the difference between REST and HTTP APIs, how to create endpoints, connect to Lambda functions, and secure your APIs.
What is API Gateway?
Amazon API Gateway is a fully managed service that makes it easy to create APIs that act as the front door for your applications.
What API Gateway Does
- Receive HTTP requests from clients (browsers, mobile apps, other services)
- Route requests to backend services (Lambda, EC2, other AWS services)
- Transform requests/responses to match what each side expects
- Handle authentication and authorization
- Throttle requests to protect backends from overload
- Cache responses to reduce backend load and latency
Common Use Cases
| Use Case | Example |
|---|---|
| Serverless APIs | Lambda-backed REST APIs |
| Microservices | Route to different backend services |
| Mobile backends | APIs for iOS/Android apps |
| WebSocket APIs | Real-time chat, gaming, notifications |
| Legacy modernization | Add API layer to existing systems |
API Types
API Gateway offers three API types:
HTTP APIs
- Cost: Lower cost (up to 70% cheaper)
- Latency: Lower latency
- Features: Core features - routing, CORS, auth
- Best for: Lambda/HTTP backend proxies
REST APIs
- Cost: Higher cost
- Features: Full feature set - caching, request validation, API keys
- Best for: Enterprise APIs needing all features
- Types: Regional, Edge-optimized, or Private
WebSocket APIs
- Protocol: WebSocket (persistent two-way connections)
- Best for: Real-time applications (chat, gaming, live updates)
For most Lambda backends, HTTP APIs are recommended due to lower cost and latency.
Creating an HTTP API
Let's create an API that connects to a Lambda function.
Step 1: Create a Lambda Function First
- Go to Lambda console
- Create function named
hello-api - Use this code:
import json
def lambda_handler(event, context):
# Get HTTP method and path
method = event.get('requestContext', {}).get('http', {}).get('method', 'GET')
path = event.get('rawPath', '/')
# Get query parameters
params = event.get('queryStringParameters', {}) or {}
name = params.get('name', 'World')
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({
'message': f'Hello, {name}!',
'method': method,
'path': path
})
}
Step 2: Create HTTP API
- Go to API Gateway console
- Click "Create API"
- Under HTTP API, click "Build"
- Add integration:
- Integration type: Lambda
- Lambda function: hello-api
- Configure routes:
- Method: GET
- Path: /hello
- Stage name: $default (or prod, dev, etc.)
- Click "Create"
Step 3: Test Your API
Your API URL looks like:
https://abc123.execute-api.us-east-1.amazonaws.com/hello
Test it:
curl "https://abc123.execute-api.us-east-1.amazonaws.com/hello?name=Developer"
Response:
{
"message": "Hello, Developer!",
"method": "GET",
"path": "/hello"
}
Routes and Methods
Routes define how API Gateway handles incoming requests.
Route Syntax
METHOD /path
Examples:
GET /users- List usersPOST /users- Create userGET /users/{id}- Get specific userPUT /users/{id}- Update userDELETE /users/{id}- Delete user
Path Parameters
Use curly braces for dynamic path segments:
GET /users/{userId}/orders/{orderId}
Access in Lambda:
def lambda_handler(event, context):
user_id = event['pathParameters']['userId']
order_id = event['pathParameters']['orderId']
Catch-All Routes
Use {proxy+} to catch all paths:
ANY /{proxy+}
This matches any method and any path, forwarding everything to your backend.
Request and Response Handling
HTTP API Event Format
Lambda receives this event structure:
{
"version": "2.0",
"routeKey": "GET /hello",
"rawPath": "/hello",
"rawQueryString": "name=Developer",
"headers": {
"content-type": "application/json",
"authorization": "Bearer token123"
},
"queryStringParameters": {
"name": "Developer"
},
"pathParameters": {
"id": "123"
},
"body": "{\"key\": \"value\"}",
"isBase64Encoded": false,
"requestContext": {
"http": {
"method": "GET",
"path": "/hello"
}
}
}
Lambda Response Format
Return responses in this format:
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
'body': json.dumps({'data': 'value'})
}
CORS Configuration
Cross-Origin Resource Sharing (CORS) allows browsers to make requests to your API from different domains.
Configuring CORS
- In API Gateway console, select your API
- Go to "CORS"
- Configure:
- Access-Control-Allow-Origin:
*(or specific domains) - Access-Control-Allow-Headers:
content-type, authorization - Access-Control-Allow-Methods:
GET, POST, PUT, DELETE
- Access-Control-Allow-Origin:
- Save
CORS in Lambda Response
Include CORS headers in your Lambda responses:
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type,Authorization',
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE'
},
'body': json.dumps(data)
}
Authentication and Authorization
API Gateway supports several authentication methods:
JWT Authorizers
Validate JSON Web Tokens from identity providers:
-
Create authorizer:
- Type: JWT
- Identity source:
$request.header.Authorization - Issuer URL: Your identity provider URL
- Audience: Your app's client ID
-
Attach to routes
# Client sends request with token
headers = {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...'
}
Lambda Authorizers
Use a Lambda function for custom authorization logic:
def lambda_authorizer(event, context):
token = event['headers'].get('authorization', '')
# Validate token (your logic here)
if is_valid_token(token):
return {
'isAuthorized': True,
'context': {
'userId': 'user-123'
}
}
else:
return {
'isAuthorized': False
}
IAM Authorization
Use AWS credentials to sign requests:
import boto3
from aws_requests_auth.aws_auth import AWSRequestsAuth
auth = AWSRequestsAuth(
aws_access_key='AKIA...',
aws_secret_access_key='...',
aws_host='api-id.execute-api.us-east-1.amazonaws.com',
aws_region='us-east-1',
aws_service='execute-api'
)
response = requests.get(url, auth=auth)
Stages and Deployments
What are Stages?
Stages are named references to deployments:
dev- Development environmentstaging- Testing environmentprod- Production environment
Each stage has its own URL:
https://api-id.execute-api.us-east-1.amazonaws.com/dev/hello
https://api-id.execute-api.us-east-1.amazonaws.com/prod/hello
Stage Variables
Configure different values per stage:
| Variable | dev | prod |
|---|---|---|
lambdaAlias | dev | prod |
tableName | users-dev | users-prod |
logLevel | DEBUG | INFO |
Access in Lambda:
stage = event['requestContext']['stage']
Throttling and Quotas
Protect your backend from too many requests:
Throttling
- Burst limit: Max requests in a short period (default: 5,000)
- Rate limit: Sustained requests per second (default: 10,000)
Configure per-route throttling to protect specific endpoints.
Usage Plans and API Keys
For third-party API consumers:
- Create API key
- Create usage plan with:
- Throttle settings (rate, burst)
- Quota (requests per day/week/month)
- Associate API key with usage plan
- Require API key on routes
Clients include key in header:
x-api-key: abc123xyz789
Monitoring and Logging
CloudWatch Metrics
API Gateway automatically publishes metrics:
- Count - Total requests
- 4XXError - Client errors
- 5XXError - Server errors
- Latency - Time to process requests
- IntegrationLatency - Time spent in backend
Access Logging
Log details about every request:
- Create CloudWatch log group
- Enable access logging in API settings
- Choose log format (CLF, JSON, or custom)
Example JSON log:
{
"requestId": "abc-123",
"ip": "192.168.1.1",
"httpMethod": "GET",
"path": "/hello",
"status": 200,
"latency": 50
}
API Gateway Pricing
HTTP APIs
- Request cost: $1.00 per million requests
- Data transfer: Standard AWS rates
REST APIs
- Request cost: $3.50 per million requests (first 333 million)
- Caching: Additional cost based on cache size
- Data transfer: Standard AWS rates
Free Tier
- 1 million HTTP API calls/month
- 1 million REST API calls/month
- For 12 months
Best Practices
API Design
- Use consistent naming conventions
- Version your API (
/v1/users) - Return appropriate HTTP status codes
- Include helpful error messages
Security
- Always use HTTPS (enforced by default)
- Implement authentication for sensitive endpoints
- Use throttling to prevent abuse
- Validate input data
Performance
- Use HTTP APIs when possible (lower latency, cost)
- Enable caching for frequently accessed data
- Keep Lambda functions warm for latency-sensitive APIs
- Use regional endpoints for single-region apps
Key Takeaways
- API Gateway creates serverless APIs that scale automatically
- HTTP APIs are recommended for most Lambda backends (lower cost/latency)
- REST APIs offer additional features like caching and API keys
- Routes define how requests map to backend integrations
- CORS must be configured for browser-based clients
- Authentication options include JWT, Lambda authorizers, and IAM
- Stages let you maintain separate environments (dev, staging, prod)
- Throttling protects backends from overload
What's Next
Your API is now accessible to clients, but for global performance you'll want to cache and distribute content closer to users. In the next lesson, we'll explore CloudFront - AWS's content delivery network.

