
Api Gateway
- 54 installs
- 850 repo stars
- Updated August 3, 2026
- awslabs/agent-plugins
api-gateway is a Claude skill for building, governing, and operating Amazon API Gateway REST, HTTP, and WebSocket APIs, including authorizers, usage plans, custom domains, and troubleshooting.
About
This skill provides guidance for building, governing, and operating APIs with Amazon API Gateway across REST, HTTP, and WebSocket types. A developer uses it to choose the right API type, configure authorizers, usage plans, throttling, custom domains, and CORS, or troubleshoot gateway errors. It supplies working SAM/CloudFormation templates from bundled reference files.
- Builds and operates Amazon API Gateway REST, HTTP, and WebSocket APIs
- Guides the API-type decision with a factor table covering cost, timeout, auth, and management features
- Covers custom domains, Lambda authorizers, usage plans, throttling, CORS, and troubleshooting 4xx/5xx errors
Api Gateway by the numbers
- 54 all-time installs (skills.sh)
- Ranked #3,212 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
api-gateway capabilities & compatibility
- Capabilities
- api development · devops
- Works with
- aws
- Use cases
- api development · devops
- Runs
- Local or remote
What api-gateway says it does
Build, manage, and operate APIs with Amazon API Gateway (REST, HTTP, and WebSocket).
HTTP API** is the lightweight, low-cost proxy optimized for simpler API workloads. It offers ~70% lower cost and lower latency
npx skills add https://github.com/awslabs/agent-plugins --skill api-gatewayAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 54 |
|---|---|
| repo stars | ★ 850 |
| Last updated | August 3, 2026 |
| Repository | awslabs/agent-plugins ↗ |
What it does
Build, govern, and operate Amazon API Gateway REST, HTTP, and WebSocket APIs and troubleshoot gateway errors.
Who is it for?
Designing and operating Amazon API Gateway APIs and choosing between REST, HTTP, and WebSocket
Skip if: General REST API design unrelated to AWS
When should I use this skill?
Building or troubleshooting an API Gateway REST, HTTP, or WebSocket API, or writing IaC with API Gateway resources
What you get
A correctly configured API Gateway API with the right type, auth, and IaC template.
- Configured API Gateway API
- Working SAM/CloudFormation templates
By the numbers
- 3 API types covered (REST v1, HTTP v2, WebSocket)
- HTTP API is about 70% cheaper than REST API
- REST API caching from 0.5-237 GB
Files
Amazon API Gateway Development
Expert guidance for building, managing, governing, and operating APIs with Amazon API Gateway. Covers REST APIs (v1), HTTP APIs (v2), and WebSocket APIs.
How to Use This Skill
When answering API Gateway questions:
1. Read the relevant reference file(s) before responding, do not rely solely on this summary 2. For tasks spanning multiple concerns (e.g., "private API with mTLS and custom domain"), read all relevant references 3. When the user needs IaC templates, consult references/sam-cloudformation.md or references/sam-service-integrations.md and provide complete, working SAM/CloudFormation YAML 4. Always mention relevant pitfalls and limits that affect the user's design
Quick Decision: Which API Type?
Choose the right API type first. This decision affects every downstream choice.
REST API is the full-featured API management platform for enterprises. It provides the governance, security, monetization, and operational controls that organizations need to build, publish, and manage APIs at scale, including usage plans with per-consumer throttling and quotas, API keys, request validation, WAF integration, resource policies, caching, canary deployments, and private endpoints.
HTTP API is the lightweight, low-cost proxy optimized for simpler API workloads. It offers ~70% lower cost and lower latency but trades away the API management features. Choose HTTP API when you need a fast, lightweight proxy to Lambda or HTTP backends and don't require the enterprise controls above.
| Factor | REST API (v1) | HTTP API (v2) | WebSocket API |
|---|---|---|---|
| Positioning | Full API management | Low-cost proxy | Real-time bidirectional |
| Cost | Higher | ~70% cheaper | Per-message pricing |
| Latency | Higher | Lower | Persistent connection |
| Max timeout | 50ms-29s (up to 300s Regional/Private) | 30s hard limit | 29s |
| Payload | 10 MB | 10 MB | 128 KB message / 32 KB frame |
| API Management | |||
| Usage plans/API keys | Yes | No | No |
| Request validation | Yes (JSON Schema draft 4) | No | No |
| Caching | Yes (0.5-237 GB) | No | No |
| Custom gateway responses | Yes | No | No |
| VTL mapping templates | Yes | No (parameter mapping only) | Yes |
| Security & Governance | |||
| WAF | Yes | No (use CloudFront + WAF) | No |
| Resource policies | Yes | No | No |
| Private endpoints | Yes | No | No |
| mTLS | Yes (Regional custom domain only) | Yes (Regional custom domain only) | Via CloudFront viewer mTLS |
| Auth | |||
| Lambda authorizer | Yes (TOKEN + REQUEST) | Yes (REQUEST only, simple + IAM policy format) | Yes (REQUEST on $connect only) |
| JWT authorizer | No (use Cognito authorizer) | Yes (native) | No |
| Cognito authorizer | Yes (native) | Use JWT authorizer | No |
| Operations | |||
| Canary deployments | Yes | No | No |
| Response streaming | Yes | No | No |
| X-Ray tracing | Yes | No | No |
| Execution logging | Yes | No | Yes |
| Custom domain sharing | Not with WebSocket | Not with WebSocket | Not with REST/HTTP |
Use REST API when: you are building APIs for external consumers, partners, or multi-tenant platforms; need to enforce per-consumer rate limits and quotas; require request validation, caching, or WAF at the API layer; need private endpoints, resource policies, or canary deployments; or are building an API product with monetization and governance requirements.
Use HTTP API when: you are building lightweight APIs or simple backend proxies; cost and latency are the primary concerns; you don't need per-consumer throttling, request validation, caching, or WAF at the API layer; and native JWT authorization with OIDC/OAuth 2.0 meets your auth needs. Accept the hard 30s timeout and lack of API management features. For WAF, edge caching, or edge compute, place a CloudFront distribution in front of the HTTP API.
Use WebSocket API when you need: persistent bidirectional connections for real-time use cases (chat, notifications, live dashboards).
Instructions
Step 1: Design the API
Before implementation, gather requirements systematically. Consult references/requirements-gathering.md for the full requirements workflow covering endpoints, auth, data models, performance, security, and deployment needs.
Key design decisions:
1. API type: Use the decision table above 2. Endpoint type: Edge-optimized (default for global clients; optimizes TCP connections via CloudFront POPs but does not cache at the edge), Regional (same-region clients, or global clients needing their own CloudFront distribution for edge caching, edge compute, granular WAF control, or geo-based routing), Private (VPC-only access, REST API only) 3. Topology: Centralized (single domain, path-based routing) vs Distributed (subdomains per service) 4. Authentication: See references/authentication.md for the decision tree
Step 2: Implement the API
Consult these references based on what you're building:
- Architecture patterns:
references/architecture-patterns.md: topology, multi-tenant SaaS, hybrid workloads, private APIs, multi-region, streaming - WebSocket API:
references/websocket.md: route selection, @connections management, session management, client resilience, SAM templates, limits, multi-region - Service integrations:
references/service-integrations.md: direct AWS service integrations (EventBridge, SQS, SNS, DynamoDB, Kinesis, Step Functions, S3), HTTP proxy, mock, VTL mapping templates, binary media types, Lambda sync/async invocation - Custom domains and routing:
references/custom-domains-routing.md: base path mappings, routing rules, header-based versioning - Security:
references/security.md: mTLS (API Gateway native + CloudFront viewer mTLS), TLS policies, resource policies, WAF, HttpOnly cookies, CRL checks - SAM/CloudFormation:
references/sam-cloudformation.md: IaC patterns, OpenAPI extensions, VTL reference, binary data - SAM service integration templates:
references/sam-service-integrations.md: EventBridge, SQS, DynamoDB CRUD, Kinesis, Step Functions (REST + WebSocket) templates
Step 3: Configure Performance and Scaling
- Throttling: Account-level default is 10,000 rps / 5,000 burst (adjustable; request increases via AWS Support). Configure stage-level and method-level throttling via usage plans. See
references/performance-scaling.md - Caching (REST only): Default TTL 300s, max 3600s. Only GET methods cached by default. Max cached response 1 MB
- Edge caching (all API types): For edge caching, place a self-managed CloudFront distribution in front of a Regional API. CloudFront reduces latency, backend load, AND cost (cached responses never reach API Gateway). Also enables edge compute (CloudFront Functions, Lambda@Edge) and granular cache behaviors per path. Use a Regional endpoint, not edge-optimized, when pairing with your own CloudFront distribution
- Scaling: API Gateway scales automatically but plan the entire stack (Lambda concurrency, DynamoDB capacity)
Step 4: Set Up Observability
Always configure access logging. For REST and WebSocket APIs, also enable execution logging (ERROR level for production, INFO only for debugging). HTTP API does not support execution logging; use access logs with enhanced observability variables instead.
Consult the observability references based on what you need:
- Logging setup, log formats, retention:
references/observability-logging.md - Metrics, alarms, metric filters, X-Ray tracing:
references/observability-metrics-alarms.md - Log analysis and insights, analytics pipeline, cross-account, control plane logs:
references/observability-analytics.md
Step 5: Deploy
- Use Infrastructure as Code (SAM, CDK, CloudFormation, Terraform) for production
- Canary deployments (REST only): Route a percentage of traffic to test new versions
- Blue/green deployments: Use custom domain API mappings to switch between environments with zero downtime
- Routing rules (preferred for new domains): Declarative header/path-based routing on custom domains for versioning, A/B testing, gradual rollouts, and cell-based routing
- See
references/deployment.mdfor detailed patterns
Step 6: Apply Governance
For organization-wide API standards, see references/governance.md covering:
- Preventative controls (SCPs, IAM policies)
- Proactive controls (CloudFormation Hooks, Guard rules)
- Detective controls (AWS Config rules, EventBridge)
- Specific enforcement examples for security, observability, and management
Response Format
When responding to API Gateway questions, structure your answer as:
1. Recommendation: Lead with the recommended approach and why 2. Code: Include SAM/CloudFormation YAML or code when the user needs implementation (always read the relevant reference file first) 3. Pitfalls: Warn about relevant gotchas from the pitfalls below or from references/pitfalls.md 4. Limits: Mention any service limits that constrain the design
Troubleshooting Quick Reference
When diagnosing API Gateway errors, consult references/troubleshooting.md for detailed resolution steps. Here are the most common issues:
| Error | Most Common Cause | Quick Fix |
|---|---|---|
| 400 Bad Request | Protocol mismatch (HTTP/HTTPS) with ALB | Match protocol to listener type |
| 401 Unauthorized | Wrong token type (ID vs access) or missing identity sources | Check token type matches scope config; verify all identity sources sent |
| 403 Missing Auth Token | Stage name in URL when using custom domain | Remove stage name from URL path |
| 403 from VPC | Private DNS on VPC endpoint intercepts ALL API calls | Use custom domain names for public APIs |
| 403 Access Denied | Resource policy + auth type mismatch or missing redeployment | Review policy, check auth type, redeploy API |
| 403 mTLS | Certificate issuer not in truststore or weak signature algorithm | Verify CA in truststore, use SHA-256+ |
| 429 Too Many Requests | Account/stage/method throttle limits exceeded | Implement jittered exponential backoff; request limit increase |
| 500 Internal Error | Missing Lambda invoke permission (especially with stage variables) | Add resource-based policy to Lambda function |
| 502 Bad Gateway | Lambda response not in required proxy format | Return {statusCode, headers, body} from Lambda |
| 504 Timeout | Backend exceeds 29s (REST, increasable) or 30s (HTTP, hard). HTTP API body says "Service Unavailable" but status is 504 | Optimize backend, request timeout increase (REST Regional/Private), or switch to async invocation |
| CORS errors | Missing CORS headers on Gateway Responses (4XX/5XX) | Add CORS headers to DEFAULT_4XX and DEFAULT_5XX gateway responses |
| SSL/PKIX errors | Incomplete certificate chain on backend | Provide full cert chain; use insecureSkipVerification only for testing |
Critical Pitfalls
1. REST API default timeout is 29 seconds (increasable up to 300s for Regional/Private endpoints via quota request). Lambda continues running but client gets 504. Request a timeout increase, or consider async patterns (SQS, EventBridge) for better user experience on long operations 2. HTTP API hard timeout is 30 seconds. Returns {"message":"Service Unavailable"} while Lambda continues 3. `/ping` and `/sping` are reserved paths. Do not use for API resources 4. Execution log events truncated at 1,024 bytes. Use access logs for complete data 5. 413 `REQUEST_TOO_LARGE` is the only gateway response that cannot be customized. Use DEFAULT_4XX as a catch-all to add CORS headers for all 4xx errors including 413 6. `maxItems`/`minItems` not validated in REST API request validation 7. Root-level `security` in OpenAPI is ignored. Must set per-operation 8. JWT authorizer public keys cached 2 hours. Account for this in key rotation 9. Management API rate limit: 10 rps / 40 burst. Heavy automation can hit this 10. Always redeploy REST API after configuration changes. Changes don't take effect until deployed 11. Edge-optimized endpoints do NOT cache at the edge — they only optimize TCP connections via CloudFront POPs. If you need edge caching, edge compute (CloudFront Functions, Lambda@Edge), or granular CloudFront control, use a Regional API with your own CloudFront distribution instead
For additional pitfalls (header handling, URL encoding, caching charges, canary deployments, usage plans), see references/pitfalls.md.
IaC Framework Selection
Default: CDK TypeScript
Override syntax:
- "use SAM" → Generate SAM/CloudFormation YAML templates
- "use CloudFormation" → Generate CloudFormation YAML templates
- "use Terraform" → Generate Terraform HCL
When not specified, ALWAYS use CDK TypeScript.
Error Scenarios
MCP Server Unavailable
- Inform user: "AWS Serverless MCP not responding"
- Ask: "Proceed without MCP support?"
- DO NOT continue without user confirmation
Service Limits Quick Reference
See references/service-limits.md for the complete table. Most numeric quotas below are default values and adjustable; check with your AWS account team and the latest quotas page before using them for architectural decisions. Key limits:
| Resource | REST API | HTTP API | WebSocket |
|---|---|---|---|
| Payload size | 10 MB | 10 MB | 128 KB |
| Integration timeout | 50ms-29s (up to 300s Regional/Private) | 30s hard | 29s |
| APIs per region | 600 Regional/Private; 120 Edge-optimized | 600 | 600 |
| Stages per API | 10 | 10 | 10 |
| Routes/resources per API | 300 | 300 | 300 |
| Custom domains (public) | 120 | 120 | 120 |
| Account throttle | 10,000 rps / 5,000 burst | Same | Same (shared quota) |
| API keys per region | 10,000 | N/A | N/A |
| Usage plans per region | 300 | N/A | N/A |
| Cache sizes | 0.5 GB - 237 GB | N/A | N/A |
Architecture Patterns
Topology Patterns
Three topology patterns:
1. Single AWS account: Simplest. All APIs in one account with routing rules or base path mappings 2. Separate AWS accounts per domain/application: Better isolation. Each account owns a subdomain (e.g., orders.example.com, shipping.example.com) and can contain multiple microservices behind it. No cross-account base path mappings, so subdomain-per-account is the routing mechanism 3. Central API account: Central account owns the custom domain and routes to backend APIs in other accounts. Centralized governance, throttling, metering, and observability
API Gateway as Single Entry Point
- Both single AWS account or central API account scenarios
- Map different custom domain subdomains to the same API with routing rules or different base path mappings
- Route different paths (
/service1,/service2,/docs) to different backends
Endpoint type selection:
- Regional (default): API deployed in a single region. Best when clients are in the same region or when using your own CloudFront distribution for edge caching/WAF control. Supports custom domains with ACM certificates in the same region
- Edge-optimized: Routes requests through CloudFront POPs for optimized TCP connections to global clients. Does NOT cache at the edge. For actual edge caching, use a self-managed CloudFront distribution with a Regional API. ACM certificate must be in
us-east-1 - Private: Accessible only from within a VPC via
execute-apiVPC endpoint. REST API only. See Private API Endpoints section below
Trade-offs with central account:
- X-Ray traces can span accounts using CloudWatch cross-account observability (source/monitoring account linking), but require explicit setup
- Usage plans cannot track across accounts without aggregation
- CloudWatch dashboards require aggregation in central account
Multi-Tenant SaaS Specific Concerns
- Tiered usage plans (free/pro/enterprise or bronze/silver/gold)
- Lambda authorizer validates JWT from external IdP, extracts tenant ID, retrieves per-tenant API key from DynamoDB, returns it in
usageIdentifierKeyfor transparent per-tenant throttling (seereferences/authentication.mdfor full flow) - Set
ApiKeySourceType: AUTHORIZERso API Gateway reads the key from the authorizer response, so tenants never see or manage API keys - Onboarding automation: create tenant in IdP + API key in API Gateway + mapping in DynamoDB + associate key with usage plan tier
- Forward tenant identification as custom header to backend for tenant-specific logic
- Lambda tenant isolation mode: For compute-level tenant isolation beyond throttling, create Lambda functions with
--tenancy-config '{"TenantIsolationMode": "PER_TENANT"}'. Lambda isolates execution environments per tenant: each environment is reused only for invocations from the same tenant, preventing cross-tenant data access via in-memory or/tmpstorage. API Gateway maps the tenant ID to theX-Amz-Tenant-Idheader on the Lambda integration request (e.g., from a Lambda authorizer context value viacontext.authorizer.tenantId, or from a client request header viamethod.request.header.x-tenant-idmapped tointegration.request.header.X-Amz-Tenant-Id). Tenant ID is available in the handler context object (context.tenantIdin Node.js,context.tenant_idin Python). Must be set at function creation time (cannot be changed later). Expect more cold starts since execution environments are not shared across tenants. All tenants share the function's execution role; for fine-grained per-tenant permissions, propagate tenant-scoped credentials from upstream components
Integration Patterns
API Gateway supports five integration types: AWS, AWS_PROXY, HTTP, HTTP_PROXY, and MOCK. See references/service-integrations.md for detailed configuration of each pattern.
Lambda integrations (AWS_PROXY / AWS), the most common integration type. AWS_PROXY (Lambda proxy) is the recommended default: API Gateway passes the full request to Lambda and returns the Lambda response directly, no mapping templates needed. AWS (Lambda non-proxy) allows VTL request/response transformation but requires more setup.
Direct AWS service integrations: integrate directly with AWS services without Lambda. Two implementation approaches:
- REST API and WebSocket API use
Type: AWSwith VTL mapping templates for full request/response transformation. Supports most of AWS services' actions - HTTP API uses first-class integrations (
Type: AWS_PROXYwithIntegrationSubtype) with parameter mapping instead of VTL. Supported services: EventBridge (PutEvents), SQS (SendMessage,ReceiveMessage,DeleteMessage,PurgeQueue), Kinesis (PutRecord), Step Functions (StartExecution,StartSyncExecution,StopExecution), and AppConfig (GetConfiguration). DynamoDB, SNS, and S3 are not available as HTTP API first-class integrations; use Lambda proxy instead
Most commonly used service integrations (REST API Type: AWS can integrate with any AWS service that has an HTTP API; the list below covers the most popular patterns; see references/service-integrations.md for details):
- EventBridge: event ingestion
- SQS: async message buffering
- SNS: fan-out pub/sub to multiple subscribers (REST/WebSocket only)
- DynamoDB: full CRUD with optional Streams for async processing (REST/WebSocket only)
- Kinesis Data Streams: high-throughput ordered data ingestion
- Step Functions: workflow orchestration (sync Express or async Standard).
- S3: file upload/download proxy with binary media type support (REST/WebSocket only)
HTTP integrations (HTTP / HTTP_PROXY): proxy to any HTTP endpoint (ALB, NLB, ECS, EC2, on-premises, external APIs). Use VPC Link for private backends. Available on REST and HTTP APIs. API Gateway is a valid choice for east-west (service-to-service) traffic when API management capabilities are needed beyond what load balancing provides (throttling, usage plans, request validation, authentication, and centralized observability). For internal calls that do not need these controls, prefer direct invocation (ALB, service mesh, or Lambda-to-Lambda) for lower latency and cost.
Mock integrations (Type: MOCK): responses without any backend (health checks, CORS preflight, prototyping)
Common patterns across all integrations: IAM execution roles, request validation, response mapping, Lambda sync/async invocation, backend bypass prevention (zero trust), and binary media type handling. Security note for direct service integrations: Use VTL mapping templates and API Gateway request validators. Every field that reaches the AWS service must be explicitly constructed in the mapping template. Never pass user input directly into service parameters without validation. Scope the IAM execution role to minimum required actions and specific resource ARNs (e.g., a single SQS queue, a single DynamoDB table). For S3 integrations, hardcode the bucket and validate key patterns to prevent path traversal.
Hybrid / On-Premises Workloads
Connect API Gateway to on-premises or edge applications:
1. VPC with connectivity to on-prem (VPN/Direct Connect/Transit Gateway) 2. NLB/ALB with target group using IP addresses to register on-prem server IPs 3. VPC Link to the NLB/ALB 4. API Gateway with VPC_LINK integration type
AWS Outposts: Workloads running on Outposts (EC2, ECS, ALB) can also serve as integration targets. Outposts extend the VPC into the on-premises environment, so the same VPC Link + NLB/ALB pattern applies. Register Outposts instance IPs in the NLB target group
Connectivity considerations: This pattern assumes stable, low-latency connectivity to the on-premises location. AWS Direct Connect provides the most reliable path. Site-to-Site VPN connections are inherently less stable; tunnel flaps cause NLB/ALB targets to become unreachable. With default NLB/ALB health check settings (30s interval, 3 failures), there is a ~90-second window where API Gateway sends traffic to unreachable targets, resulting in integration timeouts. Tune NLB health check intervals (10s, 2 failures) and set API Gateway integration timeouts to match your SLA. Implement a /health endpoint on the on-premises target that validates downstream dependencies. Monitor NLB/ALB UnHealthyHostCount and alarm on it
Private API Endpoints (not accessible from the public Internet)
- REST API only, accessible via VPC interface endpoint for
execute-api - Resource policy must allow access from VPC endpoint or VPC
- Deploy VPC endpoints across multiple AZs for high availability
disableExecuteApiEndpoint: trueforces traffic through custom domain only
Private API as External API Proxy
- Private APIs can proxy external/third-party APIs for workloads in isolated VPCs (no NAT gateway or internet access needed)
- API Gateway is a managed service in an AWS-managed VPC; it has internet connectivity even when your VPC does not
- Pattern: Private API (VPC endpoint) -> HTTP_PROXY integration -> external API
- Adds centralized logging, throttling, and access control to external API calls
- Security warning: This pattern effectively grants internet egress to an isolated VPC through API Gateway. Lock down the HTTP_PROXY integration to specific allowed external domains. Do not use parameterized URLs that callers can control. Apply a resource policy restricting which VPC endpoints can invoke the API. Enable full access logging. This egress path does not appear in VPC flow logs or network firewall logs, so security teams must be aware of it as a potential data exfiltration vector
Private API Cross-Account Access
- Pattern 1: VPC endpoint in consumer account + resource policy in producer account allowing
aws:SourceVpce. Combine with IAM authorization (SigV4) or Lambda authorizer for defense in depth. The resource policy controls network-level access, but without authentication any workload in the consumer VPC that can reach the VPC endpoint can invoke the API - Pattern 2: PrivateLink between accounts with VPC endpoint
- Pattern 3: Transit Gateway connecting VPCs across accounts (one of them with VPC endpoint )
Custom Domains for Private APIs
- Private custom domain names (
AWS::ApiGateway::DomainNameV2), dualstack only - Share cross-account via AWS RAM using domain name access associations
- Route 53 private hosted zone with alias record pointing to VPC endpoint regional DNS
Enforcing CloudFront as Sole Entry Point
To prevent clients from bypassing CloudFront and hitting API Gateway directly (skipping WAF, caching, geo-restrictions):
- Private API approach: Make the API Gateway endpoint private (VPC endpoint only), place CloudFront in front with VPC Origins: CloudFront → VPC Origin (internal ALB) → execute-api VPC endpoint → private API. All traffic stays within AWS private network and the API is unreachable from the public internet without CloudFront
- Regional API + restrictions (defense-in-depth, not a security boundary): Keep a regional endpoint but restrict direct access. Use a custom header from CloudFront (via origin custom headers) and validate it in a Lambda authorizer. Combine with disabling the default
execute-apiendpoint to force traffic through the custom domain fronted by CloudFront. Caveat: The header value is a static secret. If leaked through logs, source code, or developer machines, attackers can bypass CloudFront. Rotate the value regularly, store it in AWS Secrets Manager, and treat it as a credential.
On-Premises Access to Private APIs
- AWS Direct Connect or Site-to-Site VPN to reach VPC with VPC endpoint
- Route 53 Resolver inbound endpoints for on-premises DNS resolution of VPC endpoint DNS names or private custom domain
VPC Links
VPC Links enable API Gateway to reach private integration targets inside a VPC that are not publicly accessible. API Gateway creates a private connection to the VPC without exposing the backend to the internet.
- VPC Link v2 (
AWS::ApiGatewayV2::VpcLink): Supported by REST and HTTP APIs, targets ALB, NLB, and Cloud Map (for HTTP APIs) services. One VPC link per VPC can serve multiple backends. Prefer v2 for new integrations - VPC Link v1 (
AWS::ApiGateway::VpcLink): Used by WebSocket API (and legacy REST API integrations), targets NLB only - Not the same as private endpoints: A _private API endpoint_ restricts who can call the API (only from within a VPC via
execute-apiVPC endpoint). A _VPC Link_ controls where the API forwards requests to (private backends in a VPC). These are independent: a public API can use VPC Links to reach private backends, and a private API can call public HTTP endpoints without VPC Links
Multi-Region
Foundational Setup
- API Gateway custom domain names are regional resources. Create the same custom domain name (e.g.,
api.example.com) independently in each region - Each region requires its own ACM certificate for the domain. ACM certificates are also regional. Request or import in every region where the API is deployed
- Route 53 alias records point to each region's API Gateway regional domain name (the
d-xxxxxx.execute-api.{region}.amazonaws.comtarget provided when creating the custom domain) - Deploy the full stack (API Gateway, Lambda, DynamoDB, etc.) independently per region; there is no cross-region replication of API Gateway configuration
- Use IaC (SAM/CDK/Terraform) with parameterized region to ensure consistent deployments across regions
Active-Passive Failover
- Route 53 failover routing policy with health checks on the primary region
- Health checks monitor a
/healthendpoint or a CloudWatch alarm (e.g., on 5XX error rate or backend availability) - On primary failure, Route 53 automatically routes all traffic to the secondary region
- Route 53 Application Recovery Controller (ARC) for manual failover switches when automated routing is insufficient (e.g., data corruption in one region)
- RPO/RTO trade-off: Health check interval (10s or 30s) + failover propagation (~60-120s DNS TTL) determines theoretical failover speed. In practice, plan for 3-10 minutes, as many clients cache DNS aggressively beyond TTL (Java caches successful lookups indefinitely by default, mobile SDKs and corporate resolvers vary). Set Route 53 record TTL to 60s, but do not size SLAs around sub-minute failover. For faster failover, use Global Accelerator (anycast IP, no DNS propagation delay) or CloudFront with origin failover (seconds, not minutes)
Active-Active
- Route 53 latency-based or geo-based routing to nearest region
- All regions serve traffic simultaneously; both must be fully provisioned, not just on standby
- Data sovereignty: Latency-based routing may route EU users to US regions (or vice versa) if latency is lower, potentially violating GDPR or other data residency requirements. Use geo-based routing (combined with tenant locality verification) when data sovereignty is a concern. Note that DynamoDB Global Tables replicate data to all configured regions regardless of routing, so do not add regions that would violate data residency constraints
Resilient Private APIs (Multi-Region)
- Private API in each region + VPC endpoint + Custom Domain Name
- Route 53 private hosted zone with latency-based or failover routing
- Transit Gateway with inter-Region peering for VPC connectivity
- Health checks must be CloudWatch alarm-based: Route 53 health checkers run from the public internet and cannot reach private API endpoints. Create CloudWatch alarms on NLB
UnHealthyHostCount, API Gateway5XXErrorrate, or custom health metrics, then associate them with Route 53 health checks. Monitor Transit Gateway peering status separately; if inter-region peering fails, failover routing becomes critical
Response Streaming
- Still a request/response pattern: client sends a request and receives a streamed response. The connection is one-directional (server to client) and closes when the response completes. For bidirectional real-time communication, use WebSocket API (see
references/websocket.md) - REST API only; not available for HTTP API or WebSocket API
- Set
responseTransferMode: "STREAM"on integration - Supports HTTP_PROXY, Lambda proxy, and private integrations (ALB/NLB/Cloud Map backends via VPC Link)
- Lambda integrations: Use
awslambda.streamifyResponse()andHttpResponseStream.from() - HTTP integrations: Backend sends a chunked transfer-encoded response (
Transfer-Encoding: chunked); API Gateway streams chunks to the client as they arrive, with no Lambda required - First 10 MB unrestricted; beyond 10 MB bandwidth limited to 2 MB/s
- Max streaming session: 15 minutes, removing the 10 MB buffered response limit
- Idle timeouts: 5 min (Regional/Private), 30 sec (edge-optimized)
- Billing: each 10 MB of response (rounded up) = 1 request
- Limitations: No VTL response transformation, no caching, no content encoding with streaming
- Key use cases: LLM chatbot implementations that stream sentence-by-sentence for better UX; large payload delivery beyond the 10 MB buffered response limit (up to 15 minutes of streaming); real-time data feeds (logs, metrics, event streams) where partial results are useful before the full response completes; file downloads from backend services where the client can begin processing immediately
Designing APIs for AI Agent Consumption
As AI agents become API consumers, design considerations change:
- Rich documentation: API descriptions must be detailed enough for LLMs to understand intent, not just for humans
- Descriptive error messages: AI agents need enough context in error responses to retry with corrective information
- Minimize round-trips: Consider how many requests are needed to perform one action. Batch operations and intent-based APIs (e.g., "manage user" vs. separate GET/PUT/DELETE) reduce agent complexity
- Machine-friendly pagination: Use cursor-based pagination that machine consumers can follow automatically
- Resource-based vs intent-based: Consider whether traditional CRUD or intent-based endpoints better serve AI consumers
- Non-deterministic cost: AI-backed APIs have variable processing cost per request (LLM token usage varies). Factor this into monetization and usage plan design
Reducing Backend Load
- Request validation at the front door: Use API Gateway validators (headers, query strings, JSON schema) to reject bad requests before they reach the backend
- WAF rules: Block traffic from regions with no customers
- Add pagination and filters: Reduce response data volume
- Batch operations: Combine multiple small actions into single requests
- Async processing: Acknowledge request immediately, queue for backend processing at its own pace. Better for constrained backend resources
- Caching strategy: Use CloudFront caching first (reduces load, latency, AND cost, since the request never reaches API Gateway). Use API Gateway cache as fallback (reduces load and latency but NOT cost, as the request is still counted by API Gateway). See
references/performance-scaling.mdfor cache sizing, TTL configuration, and multi-layer caching details
Authentication and Authorization
Decision Tree
Is this a WebSocket API?
YES -> Lambda Authorizer (REQUEST type only on $connect; TOKEN type not
supported; cached policy applies for entire connection, must
cover all routes) or IAM (SigV4)
NO ->
Is the consumer an AWS service or resource?
YES -> IAM Authorization (SigV4)
NO -> Is the consumer a browser-based app?
YES -> Do you use Cognito?
YES -> REST API: Cognito User Pool Authorizer
HTTP API: JWT Authorizer (Cognito issuer)
NO -> Do you use another OIDC provider?
YES -> HTTP API: JWT Authorizer
REST API: Lambda Authorizer (validate JWT)
NO -> Lambda Authorizer (custom logic)
NO -> Is this machine-to-machine (M2M)?
YES -> Do you need certificate-based auth?
YES -> mTLS (Regional custom domain + S3 truststore)
NO -> OAuth 2.0 Client Credentials Grant (Cognito + JWT/Cognito authorizer)
NO -> Lambda Authorizer (most flexible)IAM Authorization (SigV4)
- Works for REST, HTTP, and WebSocket APIs (WebSocket: evaluated on
$connectonly) - Caller signs requests with AWS Signature Version 4
- Best for: AWS-to-AWS service calls, Cognito identity pools, resources already integrated with IAM
- Cross-account REST API: Requires BOTH IAM policy (caller account) AND resource policy (API account)
- Cross-account HTTP API: No resource policies; use
sts:AssumeRoleto assume a role in the API account - Multi-region: SigV4 signatures are region-specific: the signing region must match the region receiving the request. In multi-region deployments with Route 53 failover or latency-based routing, clients signing for one region will get auth failures if routed to another. SigV4a (multi-region signing) is not supported by API Gateway. Workarounds: use a region-agnostic auth mechanism (Lambda authorizer, JWT) for multi-region APIs, or implement client-side retry logic that re-signs for the correct region on auth failure
Lambda Authorizers
REST API
- TOKEN type: Receives a single header value (typically
Authorization) as input. Returns IAM policy document. If the identity source header is missing, API Gateway returns 401 immediately without invoking the Lambda; the authorizer function never gets the chance to handle missing tokens - REQUEST type: Receives headers, query strings, stage variables, and context variables as input. Returns IAM policy document. When caching is enabled and identity sources are specified, a request missing any identity source returns 401 without invoking the Lambda
- Both types must return
principalId(string identifying the caller) alongside the policy document. MissingprincipalIdcauses 500 Internal Server Error - Response limits: IAM policy document max ~8 KB. Exceeding this or returning a malformed response causes 500 Internal Server Error (not 401/403), a common debugging pitfall
- Caching: TTL default 300s, max 3600s. Cache key is the token value (TOKEN type) or identity sources (REQUEST type). When caching is enabled, the IAM policy returned by the first request is reused for subsequent requests with the same cache key. If that policy only covers specific resources (e.g., the path of the initial request), subsequent requests to other paths will be denied by the cached partial policy, causing hard-to-troubleshoot failures where clients intermittently cannot access parts of the API. Always generate IAM policies that cover the entire API when caching is enabled
HTTP API
- Simple response format: Returns
{isAuthorized: true/false, context: {...}}, much simpler than IAM policy - IAM policy format: Also supported for more complex authorization. When using IAM policy format with caching, the same full-API policy guidance from REST API applies; see REST API caching note above
- Identity sources:
$request.header.X,$request.querystring.X,$context.X,$stageVariables.X - Caching: Disabled by default (TTL=0), unlike REST API (TTL=300s). Add
$context.routeKeyto identity sources to cache per-route when enabling caching - Timeout: 10,000ms max
JWT Authorizers (HTTP API Only)
- Validates:
iss,aud/client_id,exp,nbf(must be before current time),iat(must be before current time),scope/scp(against route-configured scopes). Useskidfor JWKS key lookup. Request is denied if any validation fails - Only RSA-based algorithms supported (RS256, RS384, RS512). ECDSA (ES256, ES384, ES512) is not supported. If your IdP signs tokens with ECDSA, use a Lambda authorizer instead
- Public key cached for 2 hours; account for this in key rotation
- Token validation runs on every request (no result caching); only the JWKS public keys are cached (2 hours). This differs from REST API Cognito authorizer which caches the validation result
- JWKS endpoint timeout: 1,500ms
- Max audiences per authorizer: 50. Max scopes per route: 10
- Use access tokens with scopes for authorization. ID tokens also work when no scopes are configured on the route, but access tokens are preferred for API authorization
- Only supports self-contained JWTs; opaque access tokens are not supported. If your IdP issues opaque tokens by default, use a Lambda authorizer instead
- Works natively with Cognito, Auth0, Okta, and any OIDC-compliant provider
Cognito User Pools (REST API)
- Native authorizer type for REST APIs
- When no OAuth scopes configured on the method: use ID token
- When scopes configured: use access token
- Set up: Create user pool, app client, configure scopes on resource server
- Token revocation not enforced: The Cognito authorizer validates tokens locally (signature + claims) and does not check revocation status with Cognito. Revoked tokens (
GlobalSignOut,AdminUserGlobalSignOut) are accepted until the token'sexptime, as revocation is invisible to local validation regardless of caching. Separately, caching (default TTL 300s) means expired tokens may be accepted for up to the TTL duration afterexp. For immediate revocation, use a Lambda authorizer with token introspection instead - M2M auth: OAuth 2.0 Client Credentials Grant (confidential app client with client ID + secret, custom resource server scopes). Also works with HTTP API JWT authorizer using Cognito as issuer
Resource Policies (REST API Only)
Four key use cases:
1. Cross-account access: Allow specific AWS accounts by specifying the account principal in the Principal field 2. IP filtering: Allow/deny CIDR ranges via aws:SourceIp (public) or aws:VpcSourceIp (private/VPC) 3. VPC restriction: Restrict to specific VPCs via aws:SourceVpc 4. VPC endpoint restriction: Restrict to specific VPC endpoints via aws:SourceVpce
Policy Evaluation
Evaluation depends on which auth type is combined with the resource policy:
- Same account + IAM or Lambda authorizer: OR logic. If the auth mechanism allows, access is granted even if the resource policy has no matching statement (silent). An explicit Deny in the resource policy still wins
- Same account + Cognito: AND logic. Both the Cognito authorizer and the resource policy must allow
- Resource policy alone (no other auth): Must explicitly allow, otherwise request is denied
- Cross-account: AND logic. BOTH resource policy AND caller auth must explicitly allow. A silent resource policy results in implicit deny. This applies regardless of auth type (IAM, Cognito, Lambda authorizer)
- An explicit Deny always wins regardless of combination
- Always redeploy the API after changing the resource policy
Mutual TLS (mTLS)
- Truststore in S3 (PEM-encoded, max 1,000 certs, max 1 MB). Certificate chain max 4 levels deep; minimum SHA-256 signature, RSA-2048 or ECDSA-256 key strength
- S3 bucket must be in the same region as API Gateway; enable versioning for rollback
- Works with Regional custom domain names for REST and HTTP APIs. Edge-optimized custom domains do not support mTLS
- WebSocket APIs do not support native mTLS; use CloudFront viewer mTLS instead (see
references/security.md) - ACM certificate required for the API Gateway domain (ACM-issued or imported) for server-side TLS. Truststore accepts CA certificates from any source (ACM Private CA, commercial CA, self-signed root); just needs PEM format
- Private APIs do not natively support mTLS. Use ALB as a reverse proxy in front: Client → ALB (mTLS verify with trust store) → VPC endpoint → Private API Gateway → backend. The ALB terminates the mTLS handshake, validates the client certificate, and forwards the request to the private API via the execute-api VPC endpoint
- Disable default endpoint: Always set
disableExecuteApiEndpoint: truewhen using mTLS; otherwise clients can bypass mTLS entirely by calling the defaultexecute-apiURL directly - CRL checks: API Gateway does not check Certificate Revocation Lists. Implement via Lambda authorizer checking against CRL in DynamoDB/S3
- Certificate propagation to backend: Use Lambda authorizer to extract subject, return in context, inject as custom header via
RequestParameters
API Keys
- Not a primary authorization mechanism (easily shared/exposed)
- Use with usage plans for throttling/quota enforcement only
- Max 10,000 API keys per region (adjustable). Imported key values must be 20-128 characters
- Key source:
HEADER(default,x-api-key) orAUTHORIZER(Lambda returns key inusageIdentifierKey) - REST API only. HTTP API does not support API keys or usage plans
Custom Domains and Routing
Custom Domain Names
Setup by Endpoint Type
- Edge-optimized: ACM certificate must be in
us-east-1. Creates an internal, AWS-managed CloudFront distribution (not visible in your CloudFront console, not configurable). Does NOT cache at the edge. For actual edge caching, use a separate CloudFront distribution with a Regional API. DNS CNAME/alias to CloudFront domain - Regional: ACM certificate must be in same region as API. DNS CNAME/alias to regional domain name (
d-xxx.execute-api.region.amazonaws.com) - Private: REST API only. Dualstack only (
AWS::ApiGateway::DomainNameV2). Domain name access associations link the domain to VPC endpoints. Route 53 alias in private hosted zone pointing to VPC endpoint regional DNS. Cross-account sharing via AWS RAM domain name access associations. ACM certificate in the same region
Certificate requirements:
- Edge-optimized: ACM-issued public certificate or certificate imported into ACM. Must be in us-east-1. Imported certificates must be manually rotated before expiration
- Regional and Private: ACM-issued public certificate or certificate imported into ACM. Private CA certificates (ACM Private CA) are only for mTLS truststores, not for the domain itself
Limits
- Public custom domains: 120/region
- Private custom domains: 50/region
- API mappings per domain: 200
- Base path max length: 300 characters
Common Issues
- CNAMEAlreadyExists (edge-optimized only): CNAME already associated with another CloudFront distribution. Delete or update existing CNAME first, or use Regional endpoint type to avoid this
- Wrong certificate returned: DNS record points to stage URL instead of API Gateway domain name target
- Deletion quota: 1 per 30 seconds. Use exponential backoff
- 403 "Missing Authentication Token": Stage name included in URL when using custom domain. Remove stage name from path
Base Path Mappings
Multi-Segment Paths
- Paths can contain forward slashes:
/sales/reporting,/sales/reporting/v2,/corp/admin - Each routes to a different API endpoint
- Use
AWS::ApiGatewayV2::DomainNameandAWS::ApiGatewayV2::ApiMappingwithApiMappingKey - Works with both REST (v1) and HTTP (v2) APIs
- Domain and APIs must be in same account and Region
- Each sub-application deployed independently
Multi-Tenant White-Label
White-label domain support allows SaaS providers to serve multiple external customers through customer-specific subdomains (e.g., customer1.example.com, customer2.example.com) while routing all traffic through a single API Gateway API. Based on the pattern described in Using API Gateway as a Single Entry Point for Web Applications and API Microservices (AWS Architecture Blog).
Setup:
1. Register a domain (e.g., example.com) and create CNAME records for each customer subdomain (customer1.example.com, customer2.example.com) via Route 53 or your DNS provider 2. Create an ACM wildcard certificate (*.example.com), which covers one subdomain level only (tenant1.example.com matches, a.tenant1.example.com does not) 3. Create a custom domain in API Gateway for each customer subdomain using the wildcard certificate. Each subdomain can have its own base path mappings or routing rules, or use a shared mapping with backend routing based on the forwarded Host header 4. Point each subdomain's CNAME record to the API Gateway domain name target 5. Forward the original Host header as a custom header to the backend so it can identify the customer:
- REST API: map
method.request.header.hosttointegration.request.header.CustomerviaRequestParameters - HTTP API: use parameter mapping:
overwriteonintegration.request.header.Customerfrom$request.header.host
Key considerations:
- The wildcard certificate applied to API Gateway allows multiple subdomains to be served by a single API endpoint
- Each customer subdomain is created as a separate custom domain in API Gateway, enabling per-customer base path mappings or routing rules
- Backend microservices use the forwarded customer header to apply customer-specific business logic
- API Gateway's request/response transformation can insert or modify headers per customer
- The 120 public custom domains per region quota limits the number of customer subdomains (request increase if needed)
Routing Rules (Preferred for New Domains)
Routing rules are the recommended approach over base path mappings for new custom domains, offering header-based routing, priority-based evaluation, and simpler management. Supports public and private REST APIs only. HTTP API and WebSocket API do not support routing rules; use base path mappings instead.
Rule Structure
- Conditions: Up to 2
MatchHeaders+ 1MatchBasePaths(AND logic) - Actions: Invoke any stage of any REST API in the same account and region
- Priority: 1-1,000,000 (lower = higher precedence, no duplicates). Leave gaps between priorities (100, 200, 300) to allow inserting new rules later. Creating a rule with a duplicate priority fails with
ConflictException - Header matching supports wildcards:
*latest(matches values ending with "latest"),alpha*(matches values starting with "alpha"),*v2*(contains). Header names are case-insensitive; header values are case-sensitive
Routing Modes
1. API mappings only (default): Traditional base path mapping behavior. Use if not adopting routing rules 2. Routing rules then API mappings: Routing rules take precedence; unmatched requests fall back to base path mappings. Use for zero-downtime migration from base path mappings to routing rules 3. Routing rules only: Recommended mode for new custom domains or after completing migration from base path mappings. Requests that match no routing rule receive a 404 response
Migration from Base Path Mappings
1. Set routing mode to "Routing rules then API mappings" — existing base path mappings continue as fallback 2. Progressively create routing rules (e.g., start with a test header rule for controlled traffic). Include a catch-all rule (no conditions) at the lowest priority as a safety net; without this, unmatched requests will receive a 404 after switching modes in step 4 3. Monitor with $context.customDomain.routingRuleIdMatched in access logs to verify routing behavior and confirm all expected traffic paths are covered by rules 4. Once all traffic is covered by rules, switch to "Routing rules only" mode
Implementation
- CloudFormation:
AWS::ApiGatewayV2::RoutingRule - Observability:
$context.customDomain.routingRuleIdMatchedin access logs - No additional charges for routing rules; standard API Gateway request pricing applies
- A rule with no conditions serves as a catch-all matching all requests
Use Cases
- API versioning: Route by
AcceptorX-API-Versionheader to different API implementations - Gradual rollouts: Route a percentage of users to new version by adding a header in application code, then gradually increase
- A/B testing: Route specific user cohorts by custom header (e.g.,
x-test-group: beta-testers) - Cell-based architecture: Route by tenant ID or hostname header to different cell backends
- Dynamic backend selection: Route by cookie value, media type, or any custom header
Header-Based API Versioning
Route API requests to different backend implementations based on a version header (REST APIs only).
- Create a routing rule per version with
MatchHeaderson the version header (e.g.,X-API-Version: v1,X-API-Version: v2) - Each rule invokes the corresponding API/stage
- Add a catch-all rule at the lowest priority to route unversioned requests to the default (latest stable) version
- Monitor with
$context.customDomain.routingRuleIdMatchedin access logs to track version adoption - No additional infrastructure, no Lambda@Edge, no DynamoDB. Purely declarative
Host Header Forwarding
- API Gateway overwrites Host header with integration endpoint hostname
- Cannot forward original Host header directly
- REST API workaround: Create custom header in Method Request, map in Integration Request:
method.request.header.host->integration.request.header.my_host - HTTP API workaround: Use parameter mapping to forward the host header:
overwriteonintegration.request.header.X-Original-Hostfrom$request.header.host
Deployment Strategies
Deployment Basics
Understanding Deployments
A Deployment in API Gateway is an immutable snapshot of your API configuration, not an action. Think of it like a git commit: changes to your API (resources, methods, integrations, authorizers) are like commits to a main branch that cannot be invoked externally. To make changes callable, you create a Deployment (snapshot) and point a Stage to it.
- Creating a Deployment = taking a snapshot of the current API state
- Deploying to a Stage = updating a stage to point to that snapshot
- Multiple stages can point to the same or different deployments
- Console "Test Invoke" bypasses deployments: it always uses the current API state (not a deployed snapshot). Bypasses IAM auth, Lambda authorizers, Cognito authorizers, API key validation, throttling, WAF, resource policies, and mTLS. Use `TestInvokeAuthorizer` to test authorizer logic separately. This is why "it works in console but not when invoked" is a common complaint
REST API
- Explicit deployment required to make changes live. Each deployment is immutable
- A stage cannot be created without a deployment (deploymentId is required in CreateStage)
- A deployment can be created without deploying to a stage (stageName is optional in CreateDeployment)
- Always redeploy after: changing resource policy, adding/modifying methods, updating integrations, configuring authorizers, modifying models or request validators
- No redeployment needed for: throttling/usage plan changes, logging configuration, caching TTL (capacity changes take effect without redeployment but cause ~4 minutes of cache unavailability during resizing), stage variable values, client certificate changes, WAF association changes (propagation takes minutes). These take effect on the stage without a new deployment
- Max 10 stages per API (adjustable via Service Quotas)
- Stage variables: max 100 per stage, referenced as
${stageVariables.variableName}in integration URIs and$stageVariables.variableNamein VTL mapping templates
HTTP API
- A stage can be created without a deployment (then updated via UpdateStage)
- Supports automatic deployments (AutoDeploy); changes deploy immediately
- Explicit deployments also supported for manual control
- AutoDeploy caveat: AutoDeploy is a security risk. It triggers a new deployment after each API management operation completes. When making multiple changes via separate API calls, intermediate states are briefly live. A new route may be deployed before its authorizer is attached, exposing an unauthenticated endpoint to the internet for seconds to minutes. Routes may also deploy before their integration or IAM role, causing 500 errors. With explicit deployments (or SAM/CDK), all configuration changes are made first, then a single deployment snapshot is created, avoiding intermediate states. Avoid AutoDeploy in production; it is a security and availability risk, not just an operational inconvenience
WebSocket API
- A stage can be created without a deployment (then updated via UpdateStage)
- Does not support automatic deployments (AutoDeploy); every change requires an explicit redeployment
Deployment Propagation
Changes do not propagate to all API Gateway data plane hosts simultaneously. During propagation:
- Some hosts serve the new deployment while others still serve the old one
- If you delete a resource (e.g., Lambda function) that the old deployment references, requests hitting hosts still propagating will get 500 errors
- Always retain old resources until propagation completes, then remove them in a subsequent deployment
Canary Deployments (REST API Only)
Route a percentage of traffic to a canary deployment for testing API configuration changes (not code changes):
1. Deploy new version to a canary 2. Configure canary traffic percentage (e.g., 10%) 3. Monitor via CloudWatch Logs (API-Gateway-Execution-Logs_<api-id>/<stage>) 4. Promote: "Promote Canary" replaces the stage's deployment with the canary's deployment and removes all canary settings in a single operation. All traffic then uses the new configuration. Note: If useStageCache: false (canary used a separate cache), the canary cache is discarded on promotion, causing a cache miss spike. Consider flushing the stage cache or setting short TTLs during canary testing 5. Rollback: Delete the canary release to revert all traffic to the base stage deployment. Setting the percentage to 0% merely stops canary traffic but does not remove canary settings, so it is not a proper rollback
- Configure via
canarySettingson a stage:percentTraffic(0.0–100.0),useStageCache(whether canary uses the stage cache or a separate one) - Canary releases test API Gateway configuration (new resources, integrations, mapping templates, authorizers), not Lambda code changes. For Lambda code canary, use Lambda aliases with weighted routing
- Monitor
Latency,5XXError,4XXErrorCloudWatch metrics filtered by canary stage to compare against the production baseline before promoting - SAM: Define canary settings programmatically with
sam deploy - Stage variable overrides supported during canary period
- For direct service integrations (DynamoDB, SQS, etc.): canary deployments are the only way to do gradual rollouts since there are no Lambda aliases involved
Manual Rollback via Deployment History (REST API)
REST APIs retain a history of all deployments. The fastest rollback mechanism is to point the stage back to a previous deployment ID using UpdateStage:
aws apigateway update-stage --rest-api-id <api-id> --stage-name <stage> \
--patch-operations op=replace,path=/deploymentId,value=<previous-deployment-id>- Near-instant — no CloudFormation involved, no new deployment created
- Use
GetDeploymentsto list available deployment IDs with creation dates - This is the recommended emergency rollback path — faster than CloudFormation rollback and avoids the drift risk (pitfall #4)
- Does not affect Lambda code — only reverts API Gateway configuration (routes, integrations, authorizers, mapping templates). For Lambda code rollback, update the alias to the previous version
- CloudFormation drift warning: After manual rollback, the stage's deploymentId diverges from what CloudFormation tracks. The next
sam deployor stack update will overwrite your manual rollback with whatever deployment CloudFormation computes. Always follow up with a proper IaC deployment to re-synchronize state
Blue/Green Zero-Downtime Deployments
Based on the blog https://aws.amazon.com/blogs/compute/zero-downtime-blue-green-deployments-with-amazon-api-gateway/
Use custom domain API mapping to switch traffic between two environments:
Architecture
1. Blue stack: Current production REST API (separate SAM stack) 2. Green stack: New version REST API (separate SAM stack) 3. Custom domain stack: Route 53 record + ACM certificate + API Gateway custom domain with API mapping
Workflow
1. Deploy blue stack 2. Deploy custom domain stack pointing to blue 3. Deploy green stack 4. Test green via its direct invoke URL 5. Update custom domain stack to activate green stack 6. Monitor and rollback by re-pointing to blue if needed (see notes on propagation below) 7. Cleanup: Delete the inactive (old) API stack first (it receives no traffic). Keep the custom domain stack and active API stack running. Only delete the custom domain stack when decommissioning the entire service. Never delete the custom domain stack while APIs are still serving traffic, as this removes the production endpoint immediately
Notes
- Propagation: API mapping changes propagate within minutes (no DNS change involved; the custom domain DNS record stays the same). During propagation, some API Gateway hosts serve the old mapping while others serve the new one
- In-flight request risk: During the propagation window, clients may receive responses from either blue or green non-deterministically. API Gateway does not maintain request affinity. Both blue and green must be fully functional and backward-compatible during transition. Persist all state in the backend (DynamoDB, SQS, etc.); do not rely on in-memory state in Lambda, as a multi-step workflow may start on blue and complete on green. Verify propagation is complete by returning a version identifier from your integration and polling until 100% of responses show the new version
- Rollback: Re-pointing to blue has the same propagation delay as the initial switch; it is not instant. Plan for minutes of mixed traffic during rollback
- External custom domain URL never changes
- Each environment is a complete, independent API deployment
Routing Rules for A/B Testing (REST API Only)
- REST API only. HTTP API and WebSocket API do not support routing rules (use base path mappings instead)
- Route specific users by header value to different API/stage combinations on a custom domain without Lambda
- Configure via
AWS::ApiGatewayV2::RoutingRuleresources with conditions (headers, base paths) and actions (target API + stage) - Combine with stage variables for flexible targeting
- Zero-downtime: Start in "Routing rules then API mappings" mode, existing mappings serve as fallback
- See
references/custom-domains-routing.mdfor rule structure, priority, and routing modes
Infrastructure as Code
For IaC framework selection (SAM vs CDK), project setup, CI/CD pipelines, and environment management, see the aws-serverless-deployment skill.
API Gateway IaC best practices:
- Embed OpenAPI specifications in IaC templates rather than defining APIs with IaC syntax directly
- Export OpenAPI specs from development tools, import into API Gateway
- Use IaC for all production deployments, not console
Deployment Pitfalls
1. Changes not taking effect: Must create a new deployment for REST APIs after any change 2. CloudFormation logical ID must change: AWS::ApiGateway::Deployment is immutable. If the logical ID stays the same, CloudFormation won't create a new deployment on subsequent stack updates. SAM and CDK auto-generate unique logical IDs by hashing the API definition, but if changes are made outside the API definition (e.g., only Lambda code changed), the hash stays the same and no new deployment is created. Fix: Change the API description or any definition field to force a new hash 3. Deleting old resources causes 5XX during propagation: If CloudFormation deletes the old Lambda function (or role, alias, etc.) while API Gateway is still propagating the new deployment, hosts still pointing to the old snapshot will return 500. Fix: Use a two-phase deployment: (1) deploy the new resources alongside the old ones with DeletionPolicy: Retain on resources being replaced, (2) after propagation completes, deploy again to remove the old resources. For Lambda aliases, point the alias to the new version but keep the old version published until propagation is confirmed 4. CloudFormation rollback creates new snapshot, not the original: When CloudFormation rolls back, it creates a new Deployment with the current API state; it does not restore the original deployment ID. If there's stack drift (e.g., manual console changes to the API), the rollback snapshots the _drifted_ state, not the last known-good state — the operator believes they rolled back to safety but are running an untested configuration. Mitigations: Avoid manual/console changes to production APIs; run aws cloudformation detect-stack-drift before relying on rollback; set up drift detection alarms. For fastest recovery, use manual rollback via deployment history (see below) instead of CloudFormation rollback 5. Limited deployment inspection: GetDeployment returns only ID, description, and date (not the API snapshot). However, you can use GetExport on a stage pointing to a deployment to retrieve the full API definition as OpenAPI. To diff two deployments, export from two stages pointing to different deployments and diff the exports. Track changes primarily through IaC version control 6. `DeploymentStatus: DEPLOYED` is misleading: HTTP/WebSocket API reports DEPLOYED even for deployments never associated with any stage. The status means "snapshot created successfully", not "deployed to a stage" 7. Stage variable Lambda permissions: When referencing Lambda via ${stageVariables.functionName} in an integration URI, you must manually add a resource-based invoke permission — SAM/CDK do NOT auto-generate these for stage-variable references (only for direct ARN references). Without it, every invocation returns a 500 "Internal server error" with no hint about the cause. Add permission with aws lambda add-permission --function-name <function> --statement-id apigw-<stage> --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn "arn:aws:execute-api:<region>:<account>:<api-id>/<stage>/*". This must be repeated for every new stage and every new Lambda function referenced by stage variables 8. Circular dependency: Never reference ServerlessRestApi or ServerlessHttpApi in Lambda environment variables, Outputs, IAM policy resources, or other resource properties — all of these create circular dependencies. For request-handling Lambda functions, derive API URL at runtime from event["requestContext"]. For non-request contexts (callback URLs, webhook registrations), use SSM Parameter Store — write the API URL via a post-deploy script, or use an explicit AWS::Serverless::Api resource which breaks the circular dependency 9. YAML duplicate keys: Automated template patching can silently introduce duplicate keys. Validate: sam validate or python3 -c "import yaml; yaml.safe_load(open('template.yaml'))" 10. Management API rate limit: Management API calls share an aggregate rate limit of 10 rps with 40-burst across all API Gateway operations in the account. Individual operations have stricter limits. CreateDeployment is limited to 1 request every 5 seconds (0.2 rps, fixed, not adjustable). CI/CD pipelines deploying many APIs in parallel will be throttled. CloudFormation reports a generic error, not a throttling message. Stagger parallel deployments or use a single pipeline with sequential stages 11. Cache flush on redeployment: Creating a new deployment to a stage with caching enabled flushes the entire cache, causing a temporary spike in backend load ("thundering herd"). Mitigations: (a) ensure backend auto-scaling can handle full uncached load before deploying, (b) script synthetic requests to cached endpoints after deployment to pre-warm the cache, (c) use canary deployments to limit the blast radius of cache flush, (d) backends with cold-start issues (Lambda with VPC, containers scaling from zero) compound the thundering herd — use provisioned concurrency on critical paths during deployment windows. See references/performance-scaling.md
API Governance
This document focuses on governance of REST APIs (API Gateway V1), as governance and compliance controls are primarily a concern in enterprise environments where REST APIs are the typical choice due to their full API management capabilities (usage plans, WAF, resource policies, request validation).
Governance Framework
Four types of security controls:
1. Preventative: Prevent unauthorized changes before they occur (IAM policies, SCPs) 2. Proactive: Prevent noncompliant resources before deployment (CloudFormation Hooks, Guard rules) 3. Detective: React to configuration changes after they happen (AWS Config rules, EventBridge) 4. Responsive: Remediate adverse events (automated remediation via Lambda)
Governance Tools
Preventative Controls
- IAM policies and permission boundaries: Fine-grained API Gateway control plane access
- Service Control Policies (SCPs): Organization-wide guardrails using API Gateway condition keys. Policy examples below show statement bodies only. SCPs require a complete policy document with
Version,Statementarray, and"Effect", while SCP statements implicitly apply to all principals ("Principal": "*"is not needed in SCPs but is required in resource-based policies) - Over 20 IAM condition keys available for API Gateway governance, split into two categories:
apigateway:Request/*: Evaluates the new values being set in the requestapigateway:Resource/*: Evaluates the current values on the existing resource being acted upon- Both are preventative, evaluated at IAM authorization time before the action occurs
- Key condition keys:
apigateway:Request/EndpointType,apigateway:Request/SecurityPolicy,apigateway:Resource/ApiKeyRequired,apigateway:Request/AuthorizationType,apigateway:Request/AccessLoggingDestination,apigateway:Request/MtlsTrustStoreUri
Proactive Controls
- CloudFormation Hooks: Evaluate resource configuration before deployment. Noncompliant resources block deploy or warn
- AWS Control Tower: Preconfigured proactive controls for API Gateway
- CloudFormation Guard: Open-source policy-as-code evaluation tool with declarative DSL. Managed rule set available for API Gateway
- Limitation: CloudFormation-based proactive controls may not work with non-CloudFormation IaC tools (Terraform, Pulumi)
Detective Controls
- AWS Config: Managed rules + custom rules (Guard DSL or Lambda). Key managed rules:
api-gw-xray-enabledapi-gw-associated-with-wafapi-gw-ssl-enabledapi-gw-execution-logging-enabledapi-gw-endpoint-type-check- Amazon EventBridge: React to API Gateway events in real-time with Lambda
- AWS Security Hub: Findings trigger EventBridge events for automated remediation
- AWS Trusted Advisor: Service-level checks for optimization, performance, security
Enforcing Observability
Require X-Ray Tracing
- Preventative: N/A (no IAM/SCP conditions)
- Proactive: Custom CloudFormation Hook or Guard rule
- Detective: AWS Config rule
api-gw-xray-enabled
Require Access Logging
- Preventative: SCP using
apigateway:Request/AccessLoggingDestinationandapigateway:Request/AccessLoggingFormat
{
"Effect": "Deny",
"Action": ["apigateway:PATCH", "apigateway:POST", "apigateway:PUT"],
"Resource": ["arn:aws:apigateway:*::/restapis/*/stages/*"],
"Condition": { "StringLikeIfExists": { "apigateway:Request/AccessLoggingDestination": "" } }
}- Side effect:
StringLikeIfExistsmeans any stage update that does not explicitly includeAccessLoggingDestination(e.g., updating cache settings or stage variables) will also be denied. This is intentionally strict; use detective controls instead if this is too restrictive - Detective: AWS Config custom Guard rule:
configuration.accessLogSettings.destinationArn is_string
Require Execution Logging
- Preventative: N/A (no IAM/SCP conditions)
- Proactive: Custom CloudFormation Hook or Guard rule
- Detective: AWS Config rule
api-gw-execution-logging-enabled
Caveat: Preventative/proactive controls may block first deployment via AWS Console (Console does not allow specifying these settings on new stage creation). IaC/CLI works fine.
Enforcing Security
Require WAF
- Preventative: N/A
- Proactive: Custom CloudFormation Hook
- Detective: AWS Config rule
api-gw-associated-with-waf
Require TLS 1.2+
- Preventative: SCP denying
apigateway:Request/SecurityPolicyvalueTLS_1_0 - Detective: EventBridge rule or AWS Config custom rule
Require mTLS
- Preventative: SCP requiring
apigateway:Request/MtlsTrustStoreUriis present - Detective: EventBridge rule or AWS Config custom rule
Require Specific Authorizer Type
- Preventative: SCP using
apigateway:Request/AuthorizationType(valid values:NONE,AWS_IAM,CUSTOM,COGNITO_USER_POOLS) - Use
apigateway:Request/AuthorizerUrito enforce a specific Lambda authorizer. Note: the URI is the full invocation path (arn:aws:apigateway:REGION:lambda:path/2015-03-31/functions/FUNCTION_ARN/invocations), not just the Lambda ARN. UseStringLikewith wildcards for flexibility
Require API Key
- Preventative: SCP with
apigateway:Resource/ApiKeyRequiredorapigateway:Request/ApiKeyRequired - Detective: EventBridge rule or AWS Config custom rule
Require Request Validation
- Preventative: N/A
- Proactive: Custom CloudFormation Hook
- Detective: EventBridge rule or AWS Config custom rule
Restrict VPCs in Private API Resource Policy
- Preventative: N/A
- Proactive: Custom CloudFormation Hook
- Detective: EventBridge rule or AWS Config custom rule
Audit Resource Policies for Overly Broad Access
- Preventative: N/A (resource policy content is not exposed via IAM condition keys)
- Proactive: Custom CloudFormation Hook to reject policies with
"Principal": "*"withoutConditionconstraints - Detective: AWS Config custom rule to flag resource policies granting unrestricted access (e.g., missing
aws:SourceVpceoraws:SourceIpconditions on private APIs)
Enforcing Management Control
Freeze API Modifications by Tag
{
"Effect": "Deny",
"Action": ["apigateway:DELETE", "apigateway:PATCH", "apigateway:POST", "apigateway:PUT"],
"Resource": "*",
"Condition": { "StringEquals": { "aws:ResourceTag/EnvironmentState": "frozen" } }
}- To lift freeze: temporarily disable the IAM policy. Note: the
frozentag itself cannot be removed while the policy is active (tag operations useapigateway:PUTwhich is denied) - Alternative: Freeze deployments by stage name using
apigateway:Request/StageName
Prevent Custom Domains in Child Accounts
{
"Effect": "Deny",
"Action": ["apigateway:DELETE", "apigateway:PUT", "apigateway:PATCH", "apigateway:POST"],
"Resource": ["arn:aws:apigateway:*::/domainnames", "arn:aws:apigateway:*::/domainnames/*"]
}Prevent Public APIs in Non-Central Accounts
- SCP denying
EDGEorREGIONALendpoint types in child accounts - Detective: AWS Config rule
api-gw-endpoint-type-check
Require Tags
{
"Effect": "Deny",
"Action": ["apigateway:POST"],
"Resource": ["arn:aws:apigateway:*::/restapis"],
"Condition": { "Null": { "aws:RequestTag/owner": "true" } }
}- Use
aws:RequestTagfor enforcing tags at creation time; useaws:ResourceTagfor enforcing tags on updates to existing resources - REST API child resources of RestApi, DomainName, UsagePlan inherit parent tags
Require Documentation
- Proactive: Custom CloudFormation Hook
- Detective: AWS Config custom Guard rule:
configuration.documentationVersion is_string
Require Compression
- Proactive: Custom CloudFormation Hook
- Detective: AWS Config custom Guard rule:
configuration.minimumCompressionSize >= 0
Management Access Control
API Management (Control Plane)
- IAM policy scoped to specific API ARN:
arn:aws:apigateway:region::/restapis/apiId/* - Tip: Use
arn:aws:apigateway:region::/restapis/??????????/*(10 question marks) to match any API ID. REST API IDs are observed to be exactly 10 alphanumeric characters. This scopes permissions to REST APIs without hardcoding specific IDs. Note: this length is not formally documented by AWS, but the risk of it changing is low given the installed base - This does NOT grant access to: custom domains, client certificates, VPC links, API keys, usage plans
- IAM principals denied by default
Observability Access
- Execution logs: IAM for CloudWatch Logs; use data protection policies to mask sensitive data
- Access logs: IAM for CloudWatch Logs or Firehose; control access at both Firehose AND destination
- Metrics: IAM for CloudWatch
- Traces: IAM for X-Ray
- CloudTrail: IAM for CloudTrail
- Sensitive data protection: CloudWatch Logs data protection policies, Amazon Macie for S3-stored logs
API Lifecycle
Design -> Build -> Manage -> Adoption
1. Plan: Protocol selection, endpoint type, topology, standards 2. Develop/Test: IaC, OpenAPI specs, integration testing 3. Secure: Auth, WAF, mTLS, resource policies 4. Deploy/Publish: CI/CD, canary, blue/green 5. Scale: Quotas, caching, cell-based architecture 6. Monitor: Metrics, logs, traces, dashboards 7. Insights: CloudWatch Logs Insights, Contributor Insights, QuickSight 8. Monetize: Usage plans, API segmentation, AWS Marketplace, AWS Data Exchange 9. Discover: API Gateway Portal, Backstage, partner portals (Readme, Apiable, SmartBear)
Audit
- CloudTrail: All REST API management calls captured as events
- AWS Config: Record configuration changes, detect drift, enforce compliance
- EventBridge: React to changes in real-time
- Example EventBridge rule for stage updates:
{
"detail": {
"eventSource": ["apigateway.amazonaws.com"],
"requestParameters": { "restApiId": ["abcd123456"], "stageName": ["prod"] },
"eventName": ["UpdateStage"],
"errorCode": [{ "exists": false }]
}
}Observability: Analytics and Operations
CloudWatch Logs Insights Queries
Find 5xx Errors
fields @timestamp, status, requestId, ip, resourcePath, integrationLatency
| filter status >= 500
| sort @timestamp desc
| limit 100Latency Analysis
fields @timestamp, responseLatency, integrationLatency, resourcePath
| stats avg(responseLatency) as avgLatency, max(responseLatency) as maxLatency,
avg(integrationLatency) as avgIntegration by resourcePath
| sort avgLatency descTop Talkers
fields ip
| stats count(*) as requestCount by ip
| sort requestCount desc
| limit 20Per-Domain Analytics
filter domainName like /(?i)(api.example.com)/
| stats count(*) as requests, avg(responseLatency) as avgLatency by resourcePath
| sort requests descDiagnose 403 Errors by Phase
fields @timestamp, requestId, ip, resourcePath
| filter status = 403
| stats count(*) as cnt
by coalesce(`waf-status`, "-") as waf,
coalesce(`authenticate-status`, "-") as authn,
coalesce(`authorizer-status`, "-") as authzr,
coalesce(`authorize-status`, "-") as authz
| sort cnt descFind Specific Gateway Response Types
fields @timestamp, requestId, `error-responseType`, `error-message`, status
| filter ispresent(`error-responseType`)
| stats count(*) as cnt by `error-responseType`
| sort cnt descAdditional Monitoring Tools
- CloudWatch Synthetics: Canaries for synthetic monitoring of endpoints on schedule
- CloudWatch Application Insights: Automated dashboards for problem detection
- CloudWatch Contributor Insights: Find top talkers and contributors; pre-built sample rules for API Gateway
- CloudWatch Dashboards: Include dashboard definitions in IaC templates
- CloudWatch ServiceLens: Integrates traces, metrics, logs, alarms, resource health
CloudWatch Embedded Metrics Format
- Include metric data in structured logs sent to CloudWatch Logs
- CloudWatch extracts metrics automatically (cheaper than PutMetricData API)
- Use for custom business metrics (e.g., orders per minute, revenue per endpoint)
- Include dashboard definitions in IaC templates with both operational and business metrics
AI-Assisted Operations
- CloudWatch AI Operations: Specify a time window, it correlates logs across services and generates root cause hypothesis
- Amazon Q CLI: Natural language troubleshooting ("Why do I see increased 500 errors from API Gateway in this stack?")
- CloudWatch Logs Insights: Supports natural language to query translation and auto-generated pattern summaries
API Analytics Pipeline
For deep analytics beyond CloudWatch dashboards:
1. Stream access logs via Amazon Data Firehose 2. Enrich with Lambda transformation (add business context, geo-IP lookup) 3. Store in S3 (partitioned by date/API/stage) 4. Query with Amazon Athena 5. Visualize with Amazon QuickSight
Cost tip: Firehose-to-S3 ingestion (~$0.029/GB) is significantly cheaper than CloudWatch Logs ingestion (~$0.50/GB). For high-volume APIs, stream access logs to Firehose instead of CloudWatch Logs and query with Athena. Use CloudWatch Logs for execution logs (lower volume) and real-time Logs Insights queries.
Cross-Account and Centralized Logging
For multi-account AWS Organizations setups:
1. CloudWatch cross-account observability: Use Observability Access Manager (OAM) to share metrics, logs, and traces from source accounts to a central monitoring account. Enables unified dashboards and alarms across all API Gateways 2. Subscription filters: Stream access logs from each account to a central Kinesis Data Stream or Firehose in the monitoring account for aggregated analysis 3. Consistent log group naming: Use a standard naming convention across accounts (e.g., /aws/apigateway/<account-alias>/<api-name>/access-logs) to simplify cross-account queries and cost attribution
CloudTrail
- Captures all API Gateway management calls as control plane events
- Does NOT log data plane events (actual API requests); use access logs for that
- Determines: request made, IP address, who made it, when
- Use for audit and compliance, not operational monitoring
- Do not forget CloudTrail for control plane audit: who changed API configuration and when
Observability: Logging
Execution Logging (REST API and WebSocket)
- Full request/response logs including mapping template output, integration request/response, authorizer output
- Levels: OFF, ERROR, INFO
- Log events truncated at 1,024 bytes; use access logs for complete data
- Log group:
API-Gateway-Execution-Logs_<apiId>/<stageName>(both REST and WebSocket) - HTTP API does NOT support execution logging
- Cost warning: INFO-level execution logging generates many log events per request (10-60+ depending on API complexity: authorizers, mapping templates, and integration details all add entries). At scale, CloudWatch Logs costs can exceed Lambda + API Gateway costs combined. Use ERROR level in production and enable INFO only for targeted debugging
What API Gateway Does NOT Log
- 413 Request Entity Too Large
- Excessive 429 throttling responses
- 400 errors to unmapped custom domains
- Internal 500 errors from API Gateway itself
Access Logging
- Customizable log format using
$contextvariables - Formats: CLF, JSON, XML, CSV
- Access log template max: 3 KB
- Destinations: CloudWatch Logs or Kinesis Data Firehose (REST only for Firehose)
- HTTP API: Only access logging supported (no execution logging)
- Delivery latency: Access logs can be delayed by several minutes. Use CloudWatch metrics (near-real-time) for dashboards and alarms; use access logs for investigation and deep analysis
Log Retention
CloudWatch Logs default to Never Expire, which causes unbounded storage costs. Always set retention policies:
- Execution logs (INFO): 3-7 days (debugging only, high volume)
- Execution logs (ERROR): 14-30 days
- Access logs: 30-90 days (or longer for compliance)
- Compliance/audit logs: 1-3 years per organizational policy
Define log groups explicitly in SAM/CloudFormation to control retention:
ApiAccessLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/apigateway/${MyApi}/access-logs"
RetentionInDays: 90Recommended Access Log Format (REST API)
Use this JSON format for maximum troubleshooting capability with enhanced observability variables:
Note: This format is for REST APIs. HTTP API and WebSocket API use different $context variables; see the API-specific formats below.
{
"requestId": "$context.requestId",
"extendedRequestId": "$context.extendedRequestId",
"ip": "$context.identity.sourceIp",
"caller": "$context.identity.caller",
"user": "$context.identity.user",
"accountId": "$context.identity.accountId",
"userAgent": "$context.identity.userAgent",
"requestTime": "$context.requestTime",
"requestTimeEpoch": "$context.requestTimeEpoch",
"httpMethod": "$context.httpMethod",
"resourcePath": "$context.resourcePath",
"path": "$context.path",
"status": "$context.status",
"protocol": "$context.protocol",
"responseLength": "$context.responseLength",
"responseLatency": "$context.responseLatency",
"integrationLatency": "$context.integrationLatency",
"domainName": "$context.domainName",
"apiId": "$context.apiId",
"stage": "$context.stage",
"error-message": "$context.error.message",
"error-responseType": "$context.error.responseType",
"waf-error": "$context.waf.error",
"waf-status": "$context.waf.status",
"waf-latency": "$context.waf.latency",
"waf-response": "$context.wafResponseCode",
"authenticate-error": "$context.authenticate.error",
"authenticate-status": "$context.authenticate.status",
"authenticate-latency": "$context.authenticate.latency",
"authorizer-error": "$context.authorizer.error",
"authorizer-status": "$context.authorizer.status",
"authorizer-latency": "$context.authorizer.latency",
"authorizer-integrationLatency": "$context.authorizer.integrationLatency",
"authorize-error": "$context.authorize.error",
"authorize-status": "$context.authorize.status",
"authorize-latency": "$context.authorize.latency",
"integration-error": "$context.integration.error",
"integration-status": "$context.integration.status",
"integration-latency": "$context.integration.latency",
"integration-requestId": "$context.integration.requestId",
"integration-integrationStatus": "$context.integration.integrationStatus"
}Key variables explained:
requestTimeEpoch: Epoch-millisecond timestamp. Use for programmatic analysis and Athena queriesextendedRequestId: Maps tox-amz-apigw-idheader. Needed for AWS Support escalationsaccountId: AWS account of the caller. Critical for IAM-authenticated and cross-account APIserror-message: API Gateway's own error message (e.g., "Authorizer error", "Endpoint request timed out")error-responseType: Gateway Response type triggered (e.g.,AUTHORIZER_FAILURE,INTEGRATION_TIMEOUT,THROTTLED). Categorizes errors without execution logsintegration-integrationStatus: Status code from the Lambda service itself (usually 200 even when the function errors)integration-status: Status code from your Lambda function code (for proxy integrations)
HTTP API Access Log Format
HTTP API uses different $context variables. Key differences from REST API:
- Uses
$context.routeKeyinstead of$context.resourcePath - No WAF, authenticate, or authorize phase variables (HTTP API does not have these phases)
- Authorizer variables are available (HTTP API supports JWT and Lambda authorizers)
- No execution logging; access logs are the only log source
{
"requestId": "$context.requestId",
"ip": "$context.identity.sourceIp",
"userAgent": "$context.identity.userAgent",
"requestTime": "$context.requestTime",
"requestTimeEpoch": "$context.requestTimeEpoch",
"routeKey": "$context.routeKey",
"path": "$context.path",
"status": "$context.status",
"protocol": "$context.protocol",
"responseLength": "$context.responseLength",
"responseLatency": "$context.responseLatency",
"integrationLatency": "$context.integrationLatency",
"domainName": "$context.domainName",
"apiId": "$context.apiId",
"stage": "$context.stage",
"error-message": "$context.error.message",
"authorizer-error": "$context.authorizer.error",
"integration-error": "$context.integration.error",
"integration-status": "$context.integration.status",
"integration-latency": "$context.integration.latency",
"integration-integrationStatus": "$context.integration.integrationStatus"
}WebSocket API Access Log Format
WebSocket APIs use connection-oriented variables instead of HTTP method/path:
{
"requestId": "$context.requestId",
"extendedRequestId": "$context.extendedRequestId",
"connectionId": "$context.connectionId",
"eventType": "$context.eventType",
"routeKey": "$context.routeKey",
"connectedAt": "$context.connectedAt",
"requestTime": "$context.requestTime",
"requestTimeEpoch": "$context.requestTimeEpoch",
"ip": "$context.identity.sourceIp",
"userAgent": "$context.identity.userAgent",
"accountId": "$context.identity.accountId",
"status": "$context.status",
"domainName": "$context.domainName",
"apiId": "$context.apiId",
"stage": "$context.stage",
"error-message": "$context.error.message",
"error-responseType": "$context.error.responseType",
"authorizer-error": "$context.authorizer.error",
"authorizer-status": "$context.authorizer.status",
"authorizer-latency": "$context.authorizer.latency",
"authorizer-integrationLatency": "$context.authorizer.integrationLatency",
"integration-error": "$context.integration.error",
"integration-status": "$context.integration.status",
"integration-latency": "$context.integration.latency",
"integration-requestId": "$context.integration.requestId"
}Key WebSocket-specific variables:
connectionId: Unique ID for the persistent WebSocket connectioneventType:CONNECT,MESSAGE, orDISCONNECTrouteKey: The matched route ($connect,$disconnect,$default, or custom route keys)connectedAt: Epoch timestamp when the connection was established
Enhanced Observability Variables
API Gateway divides REST API requests into phases: WAF -> Authenticate -> Authorizer -> Authorize -> Integration
Each phase exposes $context.{phase}.status, $context.{phase}.latency, and $context.{phase}.error.
Note on authorizer phase: The authorizer has both $context.authorizer.latency (total authorizer latency) and $context.authorizer.integrationLatency (time spent in the authorizer Lambda/Cognito call). The difference is API Gateway overhead for the authorizer phase.
Diagnosing 403 errors by phase:
$context.waf.status: 403= WAF blocked the request$context.authenticate.status: 403= Invalid credentials (e.g., malformed SigV4)$context.authorizer.status: 403= Lambda authorizer returned Deny policy$context.authorize.status: 403with$context.authorize.error: "The client is not authorized"= Valid credentials but insufficient permissions (resource policy or IAM policy denied)
Key distinction (Lambda proxy integration):
$context.integration.integrationStatus: Status code from the Lambda service (usually 200 even when the function throws an error)$context.integration.status: Status code from your Lambda function code (thestatusCodefield in your function's response)
Additional Access Log Variables
$context.identity.apiKey: Track which API keys are making requests$context.identity.accountId: Identify which AWS account is calling (IAM auth, cross-account)$context.domainName: Differentiate traffic across custom domains$context.customDomain.routingRuleIdMatched: Track routing rule matches$context.tlsVersion,$context.cipherSuite: Monitor TLS migration$context.authorizer.principalId: Principal from Lambda authorizer (for user-level tracing)$context.authorizer.claims.sub: Cognito user pool subject claim (for Cognito-authenticated APIs)- Response streaming (REST only):
$context.integration.responseTransferMode,$context.integration.timeToAllHeaders,$context.integration.timeToFirstContent
Setting Up Logging
Prerequisites for REST API and WebSocket
1. Create IAM role with AmazonAPIGatewayPushToCloudWatchLogs managed policy 2. Set CloudWatch log role ARN in API Gateway Settings (region-level, one-time configuration) 3. Enable logging per stage
Prerequisites for HTTP API
HTTP APIs do not use the account-level CloudWatch log role. Instead:
1. Create the CloudWatch Logs log group 2. Specify the log group ARN when configuring the stage's access logging 3. API Gateway uses a service-linked role to write logs. Ensure the log group's resource-based policy allows logs:CreateLogStream and logs:PutLogEvents from the API Gateway service principal
Missing Logs Troubleshooting
- IAM permissions incorrect (most common for REST/WebSocket)
- Log group resource policy missing (most common for HTTP API)
- Logging not enabled at stage level
- Method-level override disabling logging
- Log group does not exist (create it first or let API Gateway create it)
CloudTrail
- Captures all API Gateway management calls as control plane events
- Does NOT log data plane events (actual API requests); use access logs for that
- Determines: request made, IP address, who made it, when
- Use for audit and compliance, not operational monitoring
- Do not forget CloudTrail for control plane audit: who changed API configuration and when
Observability: Metrics, Alarms, and Tracing
CloudWatch Metrics
| Metric | Description |
|---|---|
Count | Total API requests |
Latency | Time from API Gateway receiving the request to returning the response (does not include client-to-gateway network time) |
IntegrationLatency | Time spent in backend integration |
4XXError / 4xx | Client error count. REST API: 4XXError; HTTP API: 4xx |
5XXError / 5xx | Server error count. REST API: 5XXError; HTTP API: 5xx |
CacheHitCount | Cache hits (REST only) |
CacheMissCount | Cache misses (REST only) |
DataProcessed | Amount of data processed in bytes (HTTP API only) |
- Default: metrics per API stage
- Detailed metrics: per method (enable on stage)
- Use CloudWatch Embedded Metric Format for business-specific metrics
CloudWatch Alarms
Recommended Alarms
Always configure these alarms for production APIs:
Error rate alarms:
5XXErrorrate > 1% of total requests: server errors indicate backend or configuration problems4XXErrorrate anomaly detection: spikes indicate breaking changes, auth failures, or abuseIntegrationLatencyp99 > SLA threshold: detect backend degradation before timeouts
Throttling alarm:
Countapproaching account throttle limit (10,000 rps default). Alert at 80% utilization to request limit increases proactively
Cache alarms (REST API):
- Cache hit ratio (
CacheHitCount / (CacheHitCount + CacheMissCount)) drop below threshold: indicates cache invalidation issues or misconfiguration
Alarm Examples (CloudFormation)
# REST API alarms: use ApiName dimension and 5XXError/4XXError metric names
# HTTP API alarms: use ApiId dimension and 5xx/4xx metric names instead
Api5xxAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: !Sub "${AWS::StackName}-api-5xx-errors"
MetricName: 5XXError
Namespace: AWS/ApiGateway
Dimensions:
- Name: ApiName
Value: !Ref MyApi
Statistic: Sum
Period: 60
EvaluationPeriods: 3
Threshold: 5
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
AlarmActions:
- !Ref AlertSnsTopic
ApiLatencyAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: !Sub "${AWS::StackName}-api-p99-latency"
MetricName: Latency
Namespace: AWS/ApiGateway
Dimensions:
- Name: ApiName
Value: !Ref MyApi
ExtendedStatistic: p99
Period: 300
EvaluationPeriods: 3
Threshold: 5000
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
AlarmActions:
- !Ref AlertSnsTopicComposite Alarms
Combine signals to reduce noise:
- High 5xx AND high latency = likely backend failure (page on-call)
- High 4xx only = likely client-side issue (lower priority)
CloudWatch Metric Filters
Create custom CloudWatch metrics from access log patterns. Metric filters run on the log group and extract numeric values or count pattern matches.
Error Count by Response Type
{ $.[\"error-responseType\"] = \"THROTTLED\" }Publishes a metric counting throttled requests. Useful since excessive 429s may not be logged by API Gateway itself.
Slow Requests
{ $.responseLatency > 5000 }Counts requests exceeding 5 seconds. Can alarm on this custom metric for tighter latency SLOs than the built-in p99.
Requests by API Key
Add "apiKey": "$context.identity.apiKey" to your log format first, then use:
{ $.apiKey != "-" }Use with metric dimensions to track per-consumer request volumes.
X-Ray Tracing
- REST API: Active tracing supported; enable per stage. API Gateway creates the trace segment and adds trace headers to integration requests
- HTTP API: X-Ray tracing is not supported. For distributed tracing, enable X-Ray active tracing on downstream Lambda functions and correlate using the
$context.integration.requestIdaccess log variable - Configure sampling rules to control costs and recording criteria
- Service map for latency visualization
- Cross-account tracing requires CloudWatch Observability Access Manager (OAM) configuration between monitoring and source accounts
Enabling X-Ray in SAM/CloudFormation
# REST API with SAM implicit API
Globals:
Api:
TracingEnabled: true
# Explicit REST API stage
MyApiStage:
Type: AWS::ApiGateway::Stage
Properties:
TracingEnabled: true
StageName: prod
RestApiId: !Ref MyApiFor end-to-end distributed tracing, enable X-Ray in both API Gateway and downstream Lambda functions (Tracing: Active in SAM function properties). Use X-Ray Groups to filter traces by error, fault, or latency thresholds.
Performance and Scaling
Throttling
Account-Level Defaults
Note: Throttling values below are default quotas; most are adjustable via AWS Support or Service Quotas console. Do not use defaults for capacity planning without checking your account's current limits. See latest quotas.
- 10,000 requests per second steady-state across all REST APIs, HTTP APIs, WebSocket APIs, and WebSocket callback APIs in a region (shared quota)
- 5,000 burst capacity (token bucket algorithm)
- These are defaults; request increases via AWS Support or Service Quotas
Stage-Level and Method-Level
- Stage/method-level default throttle: configure via MethodSettings on the stage (REST API)
- Per-consumer throttle: configure via usage plans (REST API only)
- Method-level throttling overrides stage-level
- Max method-level throttle settings per stage: 20
- Format:
resourcePath/httpMethod(e.g.,/pets/GET)
HTTP API Throttling
- Route-level throttling only (no usage plans or API keys)
- Configure via stage settings
- Limits apply globally across all callers, with no per-consumer throttling. For per-consumer rate limiting on HTTP API, implement in a Lambda authorizer or backend
Usage Plans (REST API Only)
- Quota: Requests per day, week, or month
- Throttle: Rate (requests/second) + burst
- RPS limits are per API key, not split across keys. If a usage plan allows 100 rps and has 10 keys, each key gets 100 rps (not 10 rps each)
- Combine with API keys to track and limit per-consumer usage
- Max 300 usage plans per region (adjustable), 10,000 API keys per region
- API key source:
HEADER(default,x-api-key) orAUTHORIZER(Lambda returns key inusageIdentifierKey) - Do not associate one API key with multiple usage plans that cover the same API stage; API Gateway picks one plan non-deterministically. One key per plan per stage is safe; a usage plan can have many keys
Token Bucket Algorithm
- Bucket size = burst capacity (5,000 tokens). Refill rate = steady-state rate (10,000 tokens/second)
- Each request consumes one token. If the bucket is empty, the request is throttled (429)
- The burst capacity (5,000) is the maximum number of requests that can be served in a single instant. The steady-state rate (10,000 rps) is the maximum sustained throughput. Burst is lower than steady-state because the bucket refills faster (10,000/s) than it can be drained in one instant (5,000). Over any one-second window you can sustain 10,000 rps, but an instantaneous spike cannot exceed 5,000 concurrent requests
- Throttled requests receive 429 Too Many Requests
Caching (REST API Only)
Configuration
- Cache sizes: 0.5 GB, 1.6 GB, 6.1 GB, 13.5 GB, 28.4 GB, 58.2 GB, 118 GB, 237 GB
- Default TTL: 300 seconds
- Max TTL: 3,600 seconds
- TTL=0: Disables caching
- Max cached response size: 1,048,576 bytes (1 MB)
- Only GET methods cached by default
- Cache is best-effort, not guaranteed to cache every response
- Cache charges apply per hour regardless of usage; only provision when you have a clear caching use case
Cache Keys
- Default: resource path
- Add headers, query strings, and path parameters as additional cache keys
- More cache keys = more granular caching but lower hit rate
- Include client identity into cache keys to avoid data leaks across clients
Cache Invalidation
- Client sends
Cache-Control: max-age=0header - Can require authorization for invalidation requests
- Entire stage cache can be flushed via console or API
- Automatic flush on redeployment: Creating a new deployment to a stage flushes the entire cache, causing a temporary backend load spike ("thundering herd"). See
references/deployment.mdfor mitigations
Cache Encryption
- Encryption at rest available as option when provisioning cache
Metrics
CacheHitCount,CacheMissCountin CloudWatch- Monitor miss rate to determine if cache size is adequate
Capacity Selection
1. Run a load test against the API 2. Monitor CacheHitCount, CacheMissCount, Latency 3. Start with smaller cache, scale up based on miss rates 4. Cache resizing takes time; plan ahead of peak traffic
Scaling Considerations
API Gateway Scales Automatically
- Managed service, no capacity provisioning needed
- Be aware of service quotas and request increases proactively
Scale the Entire Stack
- No point having high API Gateway quotas if backend cannot handle the load
- Consider: Lambda concurrency limits, DynamoDB provisioned capacity, RDS connection limits, ECS/EKS scaling policies
- Automatic quota management via AWS Service Quotas for proactive adjustment
Strategies for Global Scale
- Edge-optimized endpoints: Route to nearest CloudFront POP. Note: Edge-optimized endpoints do NOT cache at the edge; they only route through CloudFront POPs to optimize TCP connections. For edge caching, use a separate CloudFront distribution in front of a Regional API
- Self-managed CloudFront distribution: More control over caching, WAF, and custom behaviors. This is the only way to get actual edge caching
- Multi-region deployment: Active-active with Route 53 latency-based routing
Multi-Layer Caching Strategy
For maximum performance, layer caches:
1. CloudFront: Edge caching (reduces latency, load, AND cost, since the request never reaches API Gateway) 2. API Gateway cache (REST only): Regional caching (reduces latency and load but NOT cost, as the request is still counted) 3. Application-level cache: ElastiCache or DAX for database query caching
- CloudFront caching should be the first choice, as it provides the most benefit
API Gateway Billing Notes
- Lambda authorizer invocations are billed by Lambda even if the request is ultimately rejected by the authorizer or by throttling. This is the "Distributed Denial of Wallet" vector below
Load Shedding
- Use API Gateway request validation to reject invalid requests early (before hitting backend)
- Configure appropriate throttle limits per consumer tier
- Use WAF rate-based rules for DDoS protection
- "Distributed Denial of Wallet" risk: Without WAF, DDoS traffic invokes Lambda authorizers for every request, driving up Lambda costs (even though API Gateway itself doesn't charge for the rejected requests). WAF blocks malicious traffic before it reaches the authorizer
Cell-Based Architecture
- Use multi-account approaches for blast radius control
- Each cell has its own API Gateway, Lambda, and database
- Route traffic to cells via custom domain and routing rules
Payload Compression
API Gateway Native Compression
minimumCompressionSize: Set the smallest payload size (in bytes) to compress automatically. Range: 0 bytes to 10 MB- Test with real payloads: compressing very small payloads can actually increase the final size. Find the optimal threshold for your data
- Works bidirectionally: API Gateway decompresses incoming requests (client sends
Content-Encodingheader) before applying mapping templates, and compresses outgoing responses (client sendsAccept-Encoding: gzip) after applying response mapping templates - Most effective for text-based formats (JSON, XML, HTML, YAML). Binary data (PDF, JPEG) compresses poorly
- Set on the API level (REST API and HTTP API)
- Benchmark: 1 MB JSON payload compressed to 220 KB (78% reduction), response latency improved by 110 ms
Compressed Passthrough to Lambda
- With native compression, API Gateway decompresses payloads before delivering to Lambda, so the decompressed payload is still subject to Lambda's 6 MB synchronous invoke limit
- To bypass this limit, configure
binaryMediaTypes: ["application/gzip"]so API Gateway passes compressed payloads directly to Lambda without decompressing - Lambda then handles decompression in function code, enabling transport of payloads several times larger than the 6 MB limit
- Lambda returns compressed responses with
isBase64Encoded: trueandContent-Encoding: gzipheaders
Compression Trade-offs
- Compression is CPU-intensive in Lambda, adding ~124 ms for 1 MB JSON on 1 GB ARM architecture
- Always benchmark with payloads representative of your workload before enabling
Handling Large Payloads
- 10 MB API Gateway limit (REST and HTTP): For payloads exceeding this, use S3 presigned URLs. Client uploads/downloads directly to S3, API returns the presigned URL
- 6 MB Lambda synchronous invoke limit: Use compressed passthrough (binary media types) to transport larger payloads, or use S3 presigned URLs
- Response streaming (REST API only): Supports up to 15-minute sessions, first 10 MB unrestricted then bandwidth-limited to 2 MB/s. Useful for LLM responses and large datasets
- Lambda Function URLs: Response streaming removes the 6 MB buffered response limit; streamed responses can be much larger (subject to function timeout and bandwidth)
- For SQS/EventBridge/Lambda async invocations (1 MB limit): Use compression or store payload in S3 and pass a reference in the message
Additional API Gateway Pitfalls
These supplement the critical pitfalls listed in the main skill file. Consult when designing or debugging API Gateway configurations.
Header Handling
- API Gateway drops/remaps certain headers:
Authorizationconditionally dropped on requests (when containing SigV4 signature or using IAM auth),Hostoverwritten on requests with integration endpoint hostname,Content-MD5dropped on requests. Plan accordingly for header passthrough
URL Encoding
- Pipe `|` and curly braces `{}` must be URL-encoded in REST API query strings. Semicolons `;` must be URL-encoded in HTTP and WebSocket API query strings (they cause data splitting)
Throttling
- Throttle limits are best-effort, not hard guarantees. Brief spikes above limits may occur
Caching
- Cache charges apply even when cache is empty. Only enable caching when you have a clear use case
- Edge-optimized endpoints do NOT cache at the edge. They only route through CloudFront POPs for optimized TCP connections. For actual edge caching, use a separate CloudFront distribution with a Regional API
Usage Plans and API Keys
- Do not associate one API key with multiple usage plans covering the same API stage; API Gateway picks one plan non-deterministically
- Usage plan RPS limits are per API key: 100 rps with 10 keys means each key gets 100 rps, not 10 rps each
Logging Costs
- Execution logging at INFO level generates many log events per request (10-60+ depending on API complexity). CloudWatch Logs costs can exceed Lambda + API Gateway combined at scale. Use ERROR level in production
Canary Deployments
- Canary deployments test API Gateway deployment snapshots (resources, integrations, mapping templates, authorizers), not Lambda code directly. Stage variable overrides can route canary traffic to different Lambda aliases. For Lambda code canary without API changes, use Lambda aliases with weighted routing
Management API
- Management API rate limit: 10 rps / 40 burst. Heavy automation can hit this
API Requirements Gathering Guide
When helping users define requirements for APIs built on Amazon API Gateway, guide them through a structured process. Ask one question at a time; do not overwhelm with lists of questions.
Workflow
1. Start with API purpose and overview (including multi-tenancy, topology, cost) 2. Determine the right API type (REST, HTTP, WebSocket) based on requirements 3. Progress through each category systematically (skip WebSocket section if not applicable) 4. Ask clarifying questions for gaps 5. Generate a final requirements summary for confirmation
Requirements Categories
1. API Purpose and Overview
- What problem does the API solve?
- Who are the primary consumers (browsers, mobile apps, other services, IoT devices, AI agents)?
- Expected usage volume (requests per day/hour/second)?
- Is this a public API, internal API, or partner API?
- Will AI agents or LLMs consume this API? (Affects documentation depth, error message design, pagination style, and monetization; see architecture-patterns.md "Designing APIs for AI Agent Consumption")
- Is this a multi-tenant API? (Affects throttling, isolation, and architecture; see architecture-patterns.md "Multi-Tenant SaaS")
- Per-tenant throttling tiers needed (bronze/silver/gold)? (Requires REST API usage plans)
- Tenant isolation level? (Throttling only, or compute isolation via Lambda
TenantIsolationMode: PER_TENANT?) - Noisy-neighbor prevention requirements?
- Account topology? (Single account for all APIs, separate accounts per domain/application, or central API account with centralized governance? Affects cross-account access, observability aggregation, and custom domain management)
- Cost sensitivity or budget constraints? (HTTP API is significantly cheaper than REST API but has fewer features: no caching, no WAF, no usage plans, no request validation, no VTL, hard 30s timeout. Choose based on feature needs vs cost)
2. Endpoints and Operations
- Resources to expose (users, orders, products, etc.)?
- Operations per resource (GET, POST, PUT, DELETE, PATCH)?
- URL paths and naming conventions?
- Nested resources or relationships?
- Query parameters for filtering, sorting, pagination?
- API versioning strategy? (URL path
/v1/is simplest; header-basedX-API-Versionvia routing rules is cleanest for REST API; query parameter?version=1is least recommended) - How many concurrent API versions to support?
- Deprecation and sunsetting plan for old versions?
3. Request/Response Specifications
- Data sent in request bodies?
- Required or optional headers?
- Query parameters needed?
- Response format (JSON, XML, binary)?
- Binary content types? (Images, PDFs, files require
binaryMediaTypesconfiguration; avoid*/*wildcard as it breaks Lambda proxy JSON responses) - Expected response codes for success and error scenarios?
- Need for multi-value query parameters or headers?
4. Data Models and Schemas
- Domain entities and their attributes?
- Data types for each field?
- Required vs optional fields?
- Validation rules and constraints?
- Enumerations or fixed value sets?
- Need for request body validation? (REST API only supports JSON Schema draft 4)
5. Authentication and Authorization
- Authentication method?
- IAM (SigV4): Best for AWS-to-AWS service calls
- Lambda authorizer: Custom logic, third-party IdPs, bearer tokens
- JWT authorizer: HTTP API only, automatic OIDC/OAuth 2.0 validation
- Cognito user pools: REST API native, or JWT authorizer on HTTP API
- API keys: Not for primary auth; use for throttling/metering with usage plans
- mTLS: Certificate-based, good for B2B and IoT
- Authorization model (RBAC, ABAC, resource-based)?
- Different permission levels or user roles?
- IP whitelisting or VPC restrictions needed?
- Cross-account access requirements?
6. Integration Requirements
- Backend services (Lambda, DynamoDB, RDS, ECS/EKS, on-premises)?
- Direct AWS service integrations without Lambda? REST API supports any AWS service via VTL mapping templates (SQS, EventBridge, Step Functions, S3, DynamoDB, etc.). HTTP API supports a subset via first-class integrations with parameter mapping (SQS, EventBridge, Step Functions, Kinesis, AppConfig)
- VPC integrations for private resources? (VPC Link required; REST uses NLB, HTTP uses ALB/NLB/Cloud Map)
- Does the API need to be completely private (VPC-only access)? (REST API only; requires
execute-apiVPC endpoint + resource policy) - Private API as proxy to external APIs? (Provides centralized logging, throttling, and access control for outbound calls from isolated VPCs without NAT gateway; security teams must be aware of this egress path)
- On-premises integrations? (Requires VPN/Direct Connect + NLB + VPC Link. Consider connectivity stability and health check tuning)
- Data transformations needed between request/response and backend?
- Need for response streaming (large payloads, LLM responses)? (REST API only; max 15-minute sessions, first 10 MB unrestricted then 2 MB/s bandwidth limit. No VTL response transformation, no caching with streaming)
- Binary data handling needed (images, PDFs, files)? (Configure
binaryMediaTypes; avoid*/*wildcard as it breaks Lambda proxy JSON responses) - File upload/download requirements? (Direct through API Gateway up to 10 MB, or presigned S3 URLs for larger files)
- Synchronous or asynchronous processing? (REST API default 29s timeout, increasable up to 300s for Regional/Private via quota request. HTTP API has hard 30s limit. For longer operations or better UX, consider async patterns: SQS, EventBridge, Step Functions)
7. WebSocket Requirements (if WebSocket API selected)
- Route selection expression? (e.g.,
$request.body.actionfor JSON messages) - Custom routes beyond
$connect/$disconnect/$default? - Session management strategy? (Store connectionId with user ID in DynamoDB on
$connect; GSI on user ID for targeted messaging) - Message patterns? (Request-response, server push/broadcast, targeted push to specific users)
- Expected concurrent connections and message throughput?
- Client resilience requirements? (Automatic reconnect with exponential backoff is mandatory; 2-hour max connection duration, 10-minute idle timeout require client-side handling)
- Heartbeat/keep-alive strategy? (Send periodic messages every 5-9 minutes to prevent idle timeout)
- Connection state recovery on reconnect? (Re-authenticate, re-subscribe to topics, restore application state)
- Backend message delivery? (Lambda via
@connectionsManagement API; handleGoneExceptionfor stale connections) - Multi-region WebSocket? (ConnectionId is region-specific; cross-region message propagation via EventBridge or DynamoDB Streams)
8. Performance and Scalability
- Expected peak request rates (per second)? (Account default: 10,000 rps / 5,000 burst across all APIs in a region, adjustable via Service Quotas)
- Latency requirements (target response time)?
- Need for response caching? (REST API only, TTL 0-3600s, 0.5-237 GB)
- Multi-layer caching strategy? (CloudFront edge → API Gateway regional → application-level)
- Throttling requirements (rate limit, burst limit)?
- Different throttling tiers for different consumers? (Requires REST API usage plans for per-API-key rate limits)
- Expected payload sizes? (Max 10 MB for REST/HTTP, consider presigned S3 URLs for larger files, or compressed passthrough via binary media types to exceed Lambda's 6 MB limit)
- Large payload strategy? (Presigned S3 URLs for >10 MB; response streaming for REST API up to 15-minute sessions; compressed passthrough for >6 MB Lambda payloads)
- Need for payload compression? (
minimumCompressionSizeon REST API; reduces bandwidth, latency, and data transfer costs through NAT Gateway/VPC Endpoints) - Per-tenant or per-consumer throttling tiers? (Requires REST API usage plans; HTTP API has no per-consumer throttling natively)
9. Error Handling
- Custom error response format?
- CORS headers needed on error responses?
- Specific gateway response customizations?
- How to communicate validation errors?
10. Observability
- Execution logging level (ERROR recommended for production, INFO for debugging)? (REST/WebSocket only; HTTP API does not support execution logging)
- Custom access log format requirements? (Use enhanced observability variables for phase-level troubleshooting)
- AWS X-Ray tracing needed? (REST API only)
- Custom CloudWatch metrics? (Consider CloudWatch Embedded Metrics Format for business metrics)
- Alerting requirements (latency thresholds, error rate, throttle count)?
- API analytics pipeline needed? (Firehose → S3 → Athena → QuickSight for deep analytics beyond CloudWatch)
11. Security Requirements
- AWS WAF needed? (REST API direct; HTTP API via CloudFront + WAF)
- Which WAF managed rules? (Core Rule Set, SQL injection, Known Bad Inputs, IP Reputation at minimum)
- CORS configuration (which origins, methods, headers)? Don't forget CORS headers on gateway error responses (DEFAULT_4XX, DEFAULT_5XX)
- TLS version requirements (TLS 1.2 minimum recommended)?
- mTLS for client certificate authentication? (REST/HTTP native on custom domain, or CloudFront viewer mTLS for any API type)
- Certificate revocation checking needed? (Lambda authorizer + DynamoDB, or CloudFront Connection Functions + KeyValueStore)
- Data encryption requirements? (Cache encryption at rest is off by default)
- Compliance requirements (HIPAA, PCI-DSS, SOC2)?
- Need to disable default execute-api endpoint? (Force traffic through custom domain)
- DDoS protection considerations? (WAF rate-based rules, Shield)
12. Deployment, Environment, and Testing
- How many environments (dev, staging, production)?
- Separate stacks per environment (full isolation) or stages within one API?
- Canary deployment needed? (REST API only; tests API configuration, not Lambda code)
- Blue/green deployment strategy? (Custom domain API mappings for zero-downtime switching)
- Stage variables for environment-specific config?
- CI/CD pipeline (CodePipeline, GitHub Actions, GitLab CI, etc.)?
- IaC tool (SAM, CDK, CloudFormation, Terraform)?
- Local testing approach? (
sam local start-apisupports Lambda proxy/non-proxy only; direct service integrations require a deployed dev stage or API Gateway console Test Invoke) - Integration testing strategy? (Deployed dev stage, contract testing, synthetic canaries)
- Load/performance testing plans? (Identify bottlenecks before production; test full stack, not just API Gateway)
13. Custom Domain and Routing
- Custom domain name needed?
- Endpoint type? Edge-optimized (default for global clients; optimizes TCP connections but does not cache at edge), Regional (same-region clients, or pair with own CloudFront distribution when edge caching, edge compute, granular WAF control, or geo-based routing is needed), Private (VPC-only access, REST API only)
- Multiple APIs behind one domain? REST API: use routing rules (preferred, supports header-based routing) or base path mappings. HTTP API/WebSocket: use base path mappings (routing rules are REST API only)
- Header-based routing needed? (API versioning, A/B testing, tenant routing; requires routing rules, REST API only)
- Multi-region deployment? (Active-passive failover or active-active with Route 53 latency-based routing)
- Data consistency requirements for multi-region? (DynamoDB Global Tables uses last-writer-wins; conditional writes do NOT prevent cross-region conflicts. For conflict-sensitive data, use single-region write routing or commutative operations. Data sovereignty concerns may require geo-based routing instead of latency-based)
- Cross-account topology? (Central API account with shared domain, or per-team subdomains)
14. Governance and Compliance
- Organization-wide API standards to enforce? (SCPs for preventative, CloudFormation Hooks for proactive, AWS Config for detective controls)
- Required tags on API resources?
- Control plane access restrictions? (Who can create, modify, deploy APIs)
- Audit requirements? (CloudTrail for control plane, access logs for data plane)
- API documentation and developer portal needed?
- API lifecycle management (versioning, deprecation, sunsetting)? See also "Endpoints and Operations" for versioning strategy details
Output Format
# API Requirements Summary
## Overview
- API Name: [name]
- API Type: [REST API / HTTP API / WebSocket API]
- Endpoint Type: [Edge-optimized / Regional / Private]
- Purpose: [description]
- Target Consumers: [who]
- Expected Volume: [requests/day, peak rps]
- Multi-tenant: [yes/no, isolation level]
- Account Topology: [single account / per-domain accounts / central API account]
- Cost Sensitivity: [budget constraints, API type preference]
## Endpoints
| Resource | Method | Path | Description | Auth |
| -------- | ------ | ---- | ----------- | ---- |
| ... | ... | ... | ... | ... |
## API Versioning
- Strategy: [URL path / header-based / query parameter]
- Concurrent Versions: [number]
- Deprecation Policy: [timeline, communication plan]
## Authentication and Authorization
- Method: [auth method]
- Authorization Model: [model]
- Roles/Permissions: [details]
## Data Models
[Entity definitions with attributes and types]
## Binary Data and Large Payloads
- Binary Media Types: [list or none]
- File Upload/Download: [direct API / presigned S3 URLs]
- Max Expected Payload Size: [size]
## WebSocket Requirements (if applicable)
- Route Selection Expression: [field]
- Custom Routes: [list]
- Session Management: [connection tracking strategy]
- Message Patterns: [request-response / broadcast / targeted push]
- Expected Concurrent Connections: [number]
- Client Resilience: [reconnect, heartbeat strategy]
## Performance Requirements
- Target Latency: [ms]
- Rate Limits: [requests/second]
- Burst Limit: [requests]
- Caching: [yes/no, TTL]
- Per-Tenant Throttling: [yes/no, tier structure]
## Security Requirements
- WAF: [yes/no]
- CORS: [origins, methods, headers]
- TLS: [minimum version]
- mTLS: [yes/no]
- Compliance: [standards]
## Observability
- Execution Logging: [level]
- Access Logging: [format]
- X-Ray Tracing: [yes/no]
- Key Metrics: [list]
- Alarms: [list]
## Deployment and Testing
- Environments: [list]
- Strategy: [canary/blue-green/direct]
- IaC Tool: [SAM/CDK/CloudFormation/Terraform]
- CI/CD: [pipeline tool]
- Local Testing: [sam local / deployed dev stage]
- Integration Testing: [approach]
## Custom Domain and Routing
- Domain: [domain name]
- Endpoint Type: [edge-optimized/regional/private]
- Routing: [routing rules (recommended) / base path mappings]
- Header-Based Routing: [yes/no, use case]
- Multi-region: [yes/no, strategy]
- Data Consistency: [conflict resolution strategy]
## Governance
- Tag Requirements: [required tags]
- Audit: [CloudTrail/Config requirements]
- Standards Enforcement: [SCPs/Hooks/Config rules]Related skills
FAQ
When should I choose HTTP API over REST API?
Choose HTTP API when you need a fast, low-cost proxy to Lambda or HTTP backends and don't require enterprise management features; it is about 70% cheaper with lower latency.
Does HTTP API support usage plans and API keys?
No. Usage plans, API keys, request validation, and caching are REST API features, not HTTP API.