Amazon API Gateway
Core concept: API Gateway is the fully managed "front door" for APIs โ it routes HTTP requests to Lambda, EC2, HTTP backends, or AWS services directly. It handles traffic management, CORS, authorization, throttling, and API versioning.
๐ฐ What Is API Gateway?โ
API Gateways are often confused with general-purpose reverse proxies and load balancers. To see a detailed comparison of their differences, feature matrices, and how they coexist in production, see the Reverse Proxy vs. Load Balancer vs. API Gateway Guide.
API Gateway acts as a reverse proxy between your clients (web, mobile, IoT) and your backend services. Think of it as a receptionist at an office building โ it checks credentials, routes visitors to the right floor, and manages how many visitors can enter at once.
Why Use API Gateway?โ
| Without API Gateway | With API Gateway |
|---|---|
| Manage own load balancer | Fully managed scaling |
| Build auth from scratch | Built-in Cognito/IAM/Lambda auth |
| No throttling | Per-client rate limiting |
| No caching | Built-in response caching |
| No API versioning | Stage-based versioning |
| No request validation | Schema validation |
Endpoint Types (REST API)โ
| Type | Description | Best For |
|---|---|---|
| Edge-Optimized (Default) | Routed through CloudFront edge network | Geographically distributed clients |
| Regional | Direct access in same region | Same-region clients, custom CDN setups |
| Private | VPC-only via Interface VPC Endpoint | Internal microservices |
API Typesโ
| Type | Use Case | Features | Cost |
|---|---|---|---|
| REST API | Full-featured REST | Caching, WAF, usage plans, VTL transforms, Edge/Private | Higher |
| HTTP API | Simple, low-latency | JWT auth, OIDC, auto-deploy, CORS | ~70% cheaper |
| WebSocket API | Real-time (chat, dashboards) | Connection management, stateful | Per message |
REST vs HTTP API Decision Matrixโ
| Need | REST API | HTTP API |
|---|---|---|
| Usage plans / API keys | โ | โ |
| Response caching | โ | โ |
| Resource policies / WAF | โ | โ |
| Request/response transformation (VTL) | โ | โ |
| Cognito JWT auth / OIDC | โ | โ |
| Private integrations (VPC Link) | โ (NLB) | โ (ALB, NLB, Cloud Map) |
| Lowest cost | โ | โ |
| Fastest performance | โ | โ |
If the question mentions usage plans, API keys, caching, WAF, or VTL โ REST API If the question asks for simplest or cheapest โ HTTP API
Integration Typesโ
Lambda Proxy vs Non-Proxyโ
| Feature | Lambda Proxy | Lambda Non-Proxy (Custom) |
|---|---|---|
| Request | Entire raw HTTP request passed to Lambda | API Gateway extracts/formats parameters |
| Response | Lambda MUST return {statusCode, body, headers} | Lambda returns anything; APIGW formats it |
| Transformation | โ Not possible at APIGW level | โ Uses VTL mapping templates |
| Setup | Minimal | High (requires mapping templates) |
| Error if wrong format | 502 Bad Gateway | API Gateway handles |
Mapping Templates (VTL)โ
Used in Non-Proxy integrations to transform request/response:
## Request mapping: Rename JSON field for legacy backend
#set($inputRoot = $input.path('$'))
{
"customer_name": "$inputRoot.name",
"customer_email": "$inputRoot.email",
"request_id": "$context.requestId"
}
Direct AWS Service Integrationโ
Skip Lambda entirely โ call AWS services directly:
# API Gateway โ SQS (no Lambda needed!)
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri: !Sub "arn:aws:apigateway:${AWS::Region}:sqs:path/${AWS::AccountId}/${Queue.QueueName}"
Credentials: !GetAtt ApiGatewayRole.Arn
RequestParameters:
integration.request.header.Content-Type: "'application/x-www-form-urlencoded'"
RequestTemplates:
application/json: "Action=SendMessage&MessageBody=$input.body"
Other direct integrations: DynamoDB, Kinesis, Step Functions, S3
VPC Links (Private Integrations)โ
API Gateway โ VPC Link โ NLB/ALB โ Private EC2/ECS/Fargate
- REST APIs: Connect via Network Load Balancer (NLB)
- HTTP APIs: Connect via ALB, NLB, or AWS Cloud Map
- Uses AWS PrivateLink โ traffic never leaves AWS network
Authorizersโ
1. Cognito User Pool Authorizerโ
Client โ Login to Cognito โ Receives JWT token
Client โ API Gateway (Authorization: Bearer <JWT>) โ Cognito validates โ Allow/Deny
- Built-in, no Lambda needed
- Validates JWT signature and expiration
- Cannot inspect payload or custom logic
2. Lambda Authorizer (Custom)โ
Client โ API Gateway โ Lambda Authorizer โ Returns IAM Policy
โ
{Allow/Deny, Context}
Two subtypes:
- Token-based: Receives Bearer token header
- Request-based: Receives full request context (headers, query params, path)
// Lambda Authorizer returns IAM policy
public class AuthorizerHandler implements RequestHandler<Map<String, Object>, Map<String, Object>> {
public Map<String, Object> handleRequest(Map<String, Object> event, Context context) {
String token = (String) event.get("authorizationToken");
// Validate token (JWT, API key, custom logic)
boolean isValid = validateToken(token);
String userId = extractUserId(token);
return Map.of(
"principalId", userId,
"policyDocument", Map.of(
"Version", "2012-10-17",
"Statement", List.of(Map.of(
"Action", "execute-api:Invoke",
"Effect", isValid ? "Allow" : "Deny",
"Resource", event.get("methodArn")
))
),
"context", Map.of(
"userId", userId,
"plan", "premium" // Available in $context.authorizer.plan
)
);
}
}
Caching: Results cached by TTL (0โ3600s). Set TTL=0 for dynamic permissions.
3. IAM (SigV4)โ
- Client signs request with AWS credentials (Signature V4)
- Ideal for service-to-service communication
- Combine with Resource Policies for cross-account or IP restrictions
4. Mutual TLS (mTLS)โ
- Client presents X.509 certificate to authenticate
- Requires Custom Domain Name
- Trust store (CA cert PEM file) uploaded to S3
- Used for B2B, banking, IoT
Authorizer Comparisonโ
| Authorizer | Use Case | Custom Logic | Caching |
|---|---|---|---|
| Cognito | User pools, social login | โ | Built-in |
| Lambda | Custom validation, 3rd-party tokens | โ | 0โ3600s TTL |
| IAM | AWS service-to-service | โ | N/A |
| mTLS | B2B, banking, IoT | โ | N/A |
Deployment Stages & Stage Variablesโ
API โ [dev stage] โ https://xyz.execute-api.us-east-1.amazonaws.com/dev
โ [staging] โ https://xyz.execute-api.us-east-1.amazonaws.com/staging
โ [prod stage] โ https://xyz.execute-api.us-east-1.amazonaws.com/prod
- Changes require deployment to a stage to take effect
- Stage variables = environment variables for API Gateway
Stage Variables + Lambda Aliasesโ
dev stage: lambdaAlias = "dev" โ Lambda:dev ($LATEST)
prod stage: lambdaAlias = "prod" โ Lambda:prod (version 5)
Integration URI: arn:aws:lambda:...:my-function:${stageVariables.lambdaAlias}
API Gateway needs lambda:InvokeFunction permission on each specific Lambda alias referenced by stage variables.
Canary Deploymentsโ
prod stage โ 95% โ stable deployment
โ 5% โ canary deployment (testing new changes)
CORSโ
If a browser at domain-a.com calls API Gateway at domain-b.com:
- Browser sends preflight OPTIONS request
- API Gateway responds with CORS headers
- Browser allows/blocks the actual request
For Lambda Proxy integration, your Lambda function MUST return CORS headers:
return new APIGatewayProxyResponseEvent()
.withStatusCode(200)
.withHeaders(Map.of(
"Access-Control-Allow-Origin", "https://myapp.example.com",
"Access-Control-Allow-Headers", "Content-Type,Authorization",
"Access-Control-Allow-Methods", "GET,POST,OPTIONS"
))
.withBody(responseBody);
For Non-Proxy integration, configure CORS via Mock Integration on the OPTIONS method.
Caching, Throttling & Usage Plansโ
Caching (REST API Only)โ
| Property | Value |
|---|---|
| TTL | 0.5 โ 3600 seconds (default 300s) |
| Size | 0.5 GB โ 237 GB |
| Cache key | Method + path + query params + headers |
| Invalidation | Cache-Control: max-age=0 header |
| Permission | Requires execute-api:InvalidateCache IAM permission |
| Encryption | Can be encrypted at rest |
Throttlingโ
| Limit | Value |
|---|---|
| Account limit | 10,000 RPS with burst of 5,000 |
| Per-stage/method | Configurable |
| Error | 429 Too Many Requests |
Usage Plans & API Keysโ
Usage Plan "Basic":
Rate: 100 RPS
Burst: 200
Quota: 10,000 requests/month
โ Assigned to API Key "customer-A-key"
Usage Plan "Premium":
Rate: 1000 RPS
Burst: 2000
Quota: Unlimited
โ Assigned to API Key "customer-B-key"
WebSocket APIโ
Connection Lifecycleโ
Client โ $connect โ Lambda (save connectionId to DynamoDB)
Client โ $default โ Lambda (process messages)
Client โ $disconnect โ Lambda (remove connectionId from DynamoDB)
Client โ customRoute โ Lambda (custom action)
Send Message to Clientโ
// Server pushes message to a specific connected client
ApiGatewayManagementApiClient apiClient = ApiGatewayManagementApiClient.builder()
.endpointOverride(URI.create("https://abc123.execute-api.us-east-1.amazonaws.com/prod"))
.build();
apiClient.postToConnection(PostToConnectionRequest.builder()
.connectionId("AbCdEfG=")
.data(SdkBytes.fromUtf8String("{\"message\": \"Hello from server!\"}"))
.build());
Request Validationโ
API Gateway can validate requests before invoking the backend:
{
"type": "object",
"required": ["name", "email"],
"properties": {
"name": { "type": "string", "minLength": 1, "maxLength": 100 },
"email": { "type": "string", "format": "email" },
"age": { "type": "integer", "minimum": 0, "maximum": 150 }
}
}
Returns 400 Bad Request if validation fails โ no Lambda invocation (saves cost!).
Common Error Codesโ
| Code | Meaning | Exam Context |
|---|---|---|
| 400 | Bad Request | Failed request validation |
| 403 | Forbidden | WAF blocked, missing API key, authorizer denied |
| 429 | Too Many Requests | Throttling limit exceeded |
| 502 | Bad Gateway | Lambda response format wrong (proxy integration) |
| 503 | Service Unavailable | Backend down or Lambda out of concurrency |
| 504 | Gateway Timeout | Lambda >29s (API Gateway hard limit) |
- 502 = Lambda returned wrong format (missing
statusCode/body) - 504 = Lambda took longer than 29 seconds (API Gateway timeout limit, NOT Lambda's 15 min limit)
๐ Best Practicesโ
- Use HTTP API when you don't need REST-specific features โ 70% cheaper
- Cache responses to reduce Lambda invocations and latency
- Enable request validation to reject bad requests before invoking backend
- Use stage variables for environment-specific configuration
- Direct service integrations when Lambda is just a pass-through
- Lambda Authorizer caching โ set appropriate TTL to reduce auth calls
- Custom domains for professional, versioned APIs
๐ฏ DVA-C02 Exam Tipsโ
- 502 = Lambda proxy response format wrong. 504 = timeout >29s
- Usage plans + API keys = per-customer throttling/quotas (REST only)
- Stage variables route stages to different Lambda aliases
- HTTP API = cheapest, simplest. REST API = full-featured
- Lambda Proxy = Lambda must return
{statusCode, body, headers} - VTL mapping templates = Non-Proxy integration only
- CORS in proxy mode = Lambda must return CORS headers
- Canary deployment = gradual traffic shift to new API deployment
- Cache invalidation needs
execute-api:InvalidateCachepermission - WebSocket =
$connect,$disconnect,$defaultroutes
๐งช Practice Questionsโ
Q1. Throttle API per customer and charge by usage tier. What feature?
A) Stage Variables
B) Lambda Reserved Concurrency
C) Usage Plans with API Keys
D) Cognito User Pools
โ Answer & Explanation
C โ Usage Plans define throttle rates and quotas per API Key per customer.
Q2. Cached API but admins need to bypass cache. How?
A) Lambda Authorizer skips cache
B) Separate cached/uncached stages
C) Cache-Control: max-age=0 header with IAM permission
D) Disable caching for admin routes
โ Answer & Explanation
C โ Clients with execute-api:InvalidateCache permission can send Cache-Control: max-age=0.
Q3. Lambda Proxy returns 502 but Lambda logs show success. Cause?
A) Lambda timeout
B) Lambda returned wrong response format
C) Missing API key
D) Missing invoke permission
โ Answer & Explanation
B โ Lambda Proxy requires {statusCode, body, headers}. Raw string or wrong format โ 502. Timeout โ 504.
Q4. Route dev stage to Lambda $LATEST and prod to v1 alias. Least effort?
A) Two API Gateways
B) Hardcode ARN per stage
C) Stage Variables referencing Lambda alias in Integration URI
D) Mapping template
โ Answer & Explanation
C โ Stage variable lambdaAlias in the URI ${stageVariables.lambdaAlias} resolves per stage.
Q5. API must call a private ALB in VPC. Which integration?
A) Lambda Proxy
B) VPC Link (HTTP API โ ALB)
C) Direct HTTP integration
D) Mock integration
โ Answer & Explanation
B โ VPC Links connect API Gateway to private resources via PrivateLink. HTTP API supports ALB/NLB; REST API supports NLB only.
Interview Questions (Senior Level)โ
- How would you design per-tenant rate limiting and monetization while keeping a migration path from REST to HTTP API?
- When would you choose VPC Link private integrations over direct Lambda?
- How do you handle sporadic
502from Lambda proxy integration?