AWS API Gateway is the front door to your serverless applications, handling millions of API calls while providing authentication, rate limiting, monitoring, and more. However, to build robust, scalable APIs, you need to understand the key patterns and best practices that separate production-ready APIs from basic implementations.
In this comprehensive guide, we'll explore proven API Gateway patterns, authentication strategies, performance optimizations, and monitoring approaches that will help you build APIs that scale.
API Gateway Types and When to Use Each
REST API vs HTTP API vs WebSocket API
Understanding which API Gateway type to use is crucial for your architecture:
When to Use Each Type:
- REST API: Full feature set, request/response transformations, detailed monitoring
- HTTP API: Lower cost, better performance, JWT authorizers, OIDC/OAuth2
- WebSocket API: Real-time bidirectional communication, chat applications, live updates
Authentication and Authorization Patterns
JWT Authorizer with Cognito
The most common pattern for modern web applications combines Cognito User Pools with JWT authorizers:
Resources:
HttpApi:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: MyHttpApi
ProtocolType: HTTP
CorsConfiguration:
AllowOrigins:
- "https://myapp.com"
AllowMethods:
- GET
- POST
- PUT
- DELETE
AllowHeaders:
- Authorization
- Content-Type
JWTAuthorizer:
Type: AWS::ApiGatewayV2::Authorizer
Properties:
ApiId: !Ref HttpApi
AuthorizerType: JWT
IdentitySource:
- $request.header.Authorization
JwtConfiguration:
Audience:
- !Ref UserPoolClient
Issuer: !Sub 'https://cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}'Lambda Authorizer for Custom Logic
When you need custom authentication logic, Lambda authorizers provide maximum flexibility:
exports.handler = async (event) => {
const token = event.authorizationToken;
try {
// Custom token validation logic
const user = await validateToken(token);
// Generate policy
const policy = generatePolicy(user.userId, 'Allow', event.methodArn);
// Add user context
policy.context = {
userId: user.userId,
email: user.email,
role: user.role
};
return policy;
} catch (error) {
// Return 401 Unauthorized
throw new Error('Unauthorized');
}
};
function generatePolicy(principalId, effect, resource) {
return {
principalId,
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: effect,
Resource: resource
}
]
}
};
}Request/Response Transformation Patterns
Input Validation with Request Models
Always validate incoming requests at the gateway level to protect your backend services:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "User Registration Model",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "User email address"
},
"password": {
"type": "string",
"minLength": 8,
"pattern": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]",
"description": "Password with complexity requirements"
},
"firstName": {
"type": "string",
"minLength": 1,
"maxLength": 50
},
"lastName": {
"type": "string",
"minLength": 1,
"maxLength": 50
}
},
"required": ["email", "password", "firstName", "lastName"],
"additionalProperties": false
}Response Transformation for Consistent APIs
Use mapping templates to ensure consistent response formats across your API:
{
"success": true,
"data": $input.json('$'),
"metadata": {
"requestId": "$context.requestId",
"timestamp": "$context.requestTime",
"version": "v1"
}
}
## Error response template
#if($context.error)
{
"success": false,
"error": {
"message": "$context.error.message",
"type": "$context.error.messageString"
},
"metadata": {
"requestId": "$context.requestId",
"timestamp": "$context.requestTime"
}
}
#endRate Limiting and Throttling Strategies
Usage Plans and API Keys
Implement tiered access with usage plans to monetize your API or provide different service levels:
Resources:
# Basic tier - 1000 requests/day, 10 req/sec burst
BasicUsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
UsagePlanName: Basic
Description: Basic tier with limited access
Throttle:
RateLimit: 5
BurstLimit: 10
Quota:
Limit: 1000
Period: DAY
ApiStages:
- ApiId: !Ref MyApi
Stage: prod
# Premium tier - 10000 requests/day, 100 req/sec burst
PremiumUsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
UsagePlanName: Premium
Description: Premium tier with higher limits
Throttle:
RateLimit: 50
BurstLimit: 100
Quota:
Limit: 10000
Period: DAY
ApiStages:
- ApiId: !Ref MyApi
Stage: prodMethod-Level Throttling
Apply different rate limits to different endpoints based on their resource requirements:
- GET endpoints: Higher rate limits (100+ req/sec)
- POST/PUT endpoints: Moderate limits (20-50 req/sec)
- Resource-intensive operations: Lower limits (5-10 req/sec)
- Authentication endpoints: Very low limits (1-2 req/sec)
Error Handling and Circuit Breaker Patterns
Gateway-Level Error Responses
Configure consistent error responses at the gateway level:
Resources:
# 429 Too Many Requests
ThrottledResponse:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref MyApi
ResponseType: THROTTLED
StatusCode: '429'
ResponseTemplates:
application/json: |
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again later.",
"retryAfter": $context.error.responseOverride.header.Retry-After
},
"requestId": "$context.requestId"
}
# 401 Unauthorized
UnauthorizedResponse:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref MyApi
ResponseType: UNAUTHORIZED
StatusCode: '401'
ResponseTemplates:
application/json: |
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing authentication credentials"
},
"requestId": "$context.requestId"
}Monitoring and Observability
Essential CloudWatch Metrics
Monitor these key metrics to ensure API health:
Key Metrics to Track:
- 4XXError: Client errors (authentication, validation)
- 5XXError: Server errors (backend failures)
- Latency: Response time distribution
- Count: Total number of API calls
- CacheHitCount/CacheMissCount: Caching effectiveness
- IntegrationLatency: Backend response time
X-Ray Tracing for Deep Insights
Enable X-Ray tracing to understand request flows and identify bottlenecks:
Resources:
MyApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: MyAPI
TracingConfig:
TracingEnabled: true
MyStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref MyApi
StageName: prod
TracingConfig:
TracingEnabled: true
AccessLogSetting:
DestinationArn: !GetAtt ApiLogGroup.Arn
Format: |
{
"requestId": "$context.requestId",
"ip": "$context.identity.sourceIp",
"caller": "$context.identity.caller",
"user": "$context.identity.user",
"requestTime": "$context.requestTime",
"httpMethod": "$context.httpMethod",
"resourcePath": "$context.resourcePath",
"status": "$context.status",
"protocol": "$context.protocol",
"responseLength": "$context.responseLength"
}Performance Optimization Patterns
Caching Strategies
Implement intelligent caching to reduce backend load and improve response times:
- Enable caching per method: Different TTLs for different endpoints
- Cache key parameters: Include query strings and headers in cache keys
- Cache invalidation: Implement cache warming and invalidation strategies
- Conditional caching: Use cache only for GET requests with specific conditions
Connection Optimization
Configure VPC Links and private integrations for better performance and security:
Resources:
VpcLink:
Type: AWS::ApiGateway::VpcLink
Properties:
Name: MyVpcLink
TargetArns:
- !Ref NetworkLoadBalancer
PrivateIntegration:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref MyApi
ResourceId: !Ref MyResource
HttpMethod: GET
AuthorizationType: AWS_IAM
Integration:
Type: HTTP_PROXY
IntegrationHttpMethod: GET
Uri: http://internal-service.local/api
ConnectionType: VPC_LINK
ConnectionId: !Ref VpcLinkSecurity Best Practices
API Security Checklist
- Enable CORS properly: Configure specific origins, not wildcards
- Use HTTPS only: Redirect HTTP to HTTPS
- Implement proper authentication: JWT, API keys, or IAM
- Validate all inputs: Use request models and mapping templates
- Rate limiting: Protect against abuse and DDoS
- Resource-based policies: Control access at the API level
- WAF integration: Protect against common web exploits
Conclusion
AWS API Gateway is a powerful service that can handle the complex requirements of modern APIs when configured correctly. By implementing these patterns and best practices, you'll build APIs that are secure, performant, and maintainable.
Start with basic authentication and rate limiting, then gradually add more sophisticated patterns like caching, monitoring, and advanced security features. Remember that a well-designed API Gateway configuration can significantly reduce the complexity of your backend services.
What API Gateway patterns have been most valuable in your projects? Share your experiences with authentication, rate limiting, or monitoring strategies!