Loading content...
When AWS launched API Gateway in 2015, it introduced a paradigm shift: what if you didn't have to manage gateway infrastructure at all? No servers to provision, no clusters to scale, no patches to apply—just define your APIs and let AWS handle everything else.
AWS API Gateway represents the opposite end of the spectrum from self-hosted solutions like Kong. Where Kong offers complete control and flexibility, AWS API Gateway trades some customization for zero operational overhead. For organizations deeply invested in AWS, this trade-off often makes compelling sense.
This page provides an exhaustive exploration of AWS API Gateway—its three distinct types, integration patterns, pricing model, performance characteristics, and the scenarios where it excels or falls short.
By the end of this page, you will understand the differences between REST API, HTTP API, and WebSocket API types; how API Gateway integrates with Lambda, ECS, and other AWS services; the cost model and how to optimize for it; performance characteristics and limitations; and when AWS API Gateway is the optimal choice versus self-hosted alternatives.
AWS API Gateway offers three distinct products, each optimized for different use cases. Understanding these differences is crucial for selecting the right type.
The original API Gateway offering, now called "REST API," provides the richest feature set:
| Feature | Capability | Use Case |
|---|---|---|
| Request Validation | JSON Schema validation, parameter validation | Reject malformed requests at the edge |
| Request/Response Transformation | VTL templates for mapping | Adapt external API to internal formats |
| API Keys & Usage Plans | Quota management, throttling per key | Monetization, partner tiers |
| Caching | Built-in response caching (0.5-237GB) | Reduce backend load, improve latency |
| Private APIs | VPC endpoints, resource policies | Internal-only APIs |
| WAF Integration | AWS WAF for request filtering | Bot protection, SQL injection blocking |
| Canary Deployments | Gradual traffic shifting | Safe deployments |
Launched in 2019, HTTP API is a streamlined, lower-cost alternative:
Trade-offs: No request validation, no VTL transformations, no caching, no API keys/usage plans, no WAF integration.
For bidirectional, real-time communication:
| Capability | REST API | HTTP API | WebSocket |
|---|---|---|---|
| Pricing (per million) | $3.50 | $1.00 | $1.00 + connection-mins |
| Added Latency | ~29ms | ~10ms | Varies |
| Request Validation | ✅ | ❌ | ❌ |
| VTL Transforms | ✅ | ❌ | ❌ |
| Response Caching | ✅ | ❌ | ❌ |
| API Keys/Usage Plans | ✅ | ❌ | ❌ |
| JWT Authorizer | ❌ (use Lambda) | ✅ | ❌ |
| Lambda Authorizer | ✅ | ✅ | ✅ |
| Private Link | ✅ | ✅ | ❌ |
| WAF Integration | ✅ | ❌ | ❌ |
Default to HTTP API for new projects—it's cheaper and faster. Use REST API only when you need its exclusive features: caching, request validation, VTL transformations, or WAF. Use WebSocket API for real-time bidirectional communication (chat, gaming, live updates).
API Gateway supports multiple integration types, each with distinct characteristics:
The flagship integration—API Gateway invokes Lambda functions directly:
1234567891011121314151617181920212223242526272829303132
AWSTemplateFormatVersion: '2010-09-09'Transform: AWS::Serverless-2016-10-31 Resources: ApiGateway: Type: AWS::Serverless::HttpApi Properties: StageName: prod CorsConfiguration: AllowOrigins: - "https://example.com" AllowMethods: - GET - POST AllowHeaders: - Content-Type - Authorization GetUserFunction: Type: AWS::Serverless::Function Properties: Handler: src/handlers/getUser.handler Runtime: nodejs18.x MemorySize: 256 Timeout: 10 Events: GetUser: Type: HttpApi Properties: ApiId: !Ref ApiGateway Path: /users/{userId} Method: GETProxy Integration (recommended): API Gateway passes the entire request to Lambda and returns the Lambda response directly. Simple, less configuration.
Custom Integration: Use VTL templates to transform request/response. More complex but allows reshaping data without Lambda code changes.
Proxy requests to any HTTP endpoint (ECS, EC2, on-premises):
12345678910
HttpIntegration: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref HttpApi IntegrationType: HTTP_PROXY IntegrationUri: !Sub 'http://${ApplicationLoadBalancer.DNSName}/api/{proxy}' IntegrationMethod: ANY PayloadFormatVersion: '1.0' ConnectionType: VPC_LINK ConnectionId: !Ref VpcLinkDirectly invoke AWS services without Lambda:
This pattern eliminates Lambda cold starts and reduces costs for simple operations.
123456789101112131415161718192021
PostToQueue: Type: AWS::ApiGateway::Method Properties: RestApiId: !Ref RestApi ResourceId: !Ref MessagesResource HttpMethod: POST AuthorizationType: AWS_IAM Integration: Type: AWS IntegrationHttpMethod: POST Uri: !Sub 'arn:aws:apigateway:${AWS:: Region }: sqs: path / ${ AWS:: AccountId } / ${ Queue.QueueName }' Credentials: !GetAtt ApiGatewayRole.Arn RequestParameters: integration.request.header.Content - Type: "'application/x-www-form-urlencoded'" RequestTemplates: application / json: 'Action=SendMessage&MessageBody=$input.body' IntegrationResponses: - StatusCode: 200 ResponseTemplates: application / json: '{"messageId": "$input.path("$.SendMessageResponse.SendMessageResult.MessageId")"}'Direct AWS service integration eliminates Lambda but requires VTL template mastery and tighter coupling to API Gateway's transformation model. Modern HTTP APIs don't support VTL, limiting this pattern to REST APIs. Evaluate whether Lambda's flexibility outweighs the cold start cost.
API Gateway provides multiple authorization mechanisms:
Requests must be signed with AWS Signature Version 4:
Integrated JWT validation with Amazon Cognito:
Authorizer:
Type: AWS:: ApiGateway:: Authorizer
Properties:
Name: CognitoAuthorizer
Type: COGNITO_USER_POOLS
RestApiId: !Ref RestApi
IdentitySource: method.request.header.Authorization
ProviderARNs:
- !GetAtt UserPool.Arn
Maximum flexibility—implement any authorization logic:
12345678910111213141516171819202122232425262728293031323334353637
import { APIGatewayTokenAuthorizerHandler, APIGatewayAuthorizerResult } from 'aws-lambda'; import jwt from 'jsonwebtoken'; export const handler: APIGatewayTokenAuthorizerHandler = async (event) => { const token = event.authorizationToken.replace('Bearer ', ''); try { const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { sub: string; scope: string }; return generatePolicy(decoded.sub, 'Allow', event.methodArn, { userId: decoded.sub, scope: decoded.scope, }); } catch (error) { return generatePolicy('unauthorized', 'Deny', event.methodArn); } }; function generatePolicy( principalId: string, effect: 'Allow' | 'Deny', resource: string, context ?: Record<string, string> ): APIGatewayAuthorizerResult { return { principalId, policyDocument: { Version: '2012-10-17', Statement: [{ Action: 'execute-api:Invoke', Effect: effect, Resource: resource, }], }, context, // Available to downstream Lambda as event.requestContext.authorizer }; }Native JWT validation without Lambda:
JwtAuthorizer:
Type: AWS:: ApiGatewayV2:: Authorizer
Properties:
ApiId: !Ref HttpApi
AuthorizerType: JWT
IdentitySource:
- $request.header.Authorization
JwtConfiguration:
Audience:
- your - api - audience
Issuer: https://your-idp.com/
Key Advantage: No Lambda cold starts, no execution costs—validation happens in API Gateway itself.
For HTTP APIs with OIDC providers (Auth0, Okta, Cognito), use JWT Authorizer—it's faster and cheaper. For REST APIs or custom logic (database lookups, complex claims), use Lambda Authorizer with caching enabled (TTL up to 3600s) to minimize invocations.
API Gateway pricing is straightforward but can surprise at scale. Understanding the model helps optimize costs.
| Component | REST API | HTTP API | WebSocket |
|---|---|---|---|
| Requests (first 333M) | $3.50/million | $1.00/million | $1.00/million |
| Requests (next 667M) | $2.80/million | $0.90/million | $0.80/million |
| Requests (over 1B) | $2.38/million | $0.80/million | $0.70/million |
| Caching (per GB-hour) | $0.02 | N/A | N/A |
| Connection minutes | N/A | N/A | $0.25/million |
| Data transfer out | Standard AWS rates | Standard AWS rates | Standard AWS rates |
Scenario: 100 million requests/month, REST API with 1GB cache
Request costs: 100M × $3.50/M = $350.00
Cache costs: 1GB × 720h × $0.02 = $14.40
Total API GW: $364.40/month
Same scenario with HTTP API:
Request costs: 100M × $1.00/M = $100.00/month
Savings: $264.40/month (73% reduction)
At billions of requests/month, API Gateway costs can exceed self-hosted alternatives. A 10B request/month workload costs ~$25,000/month on HTTP API. At this scale, evaluate whether self-hosted (Kong, Envoy) on reserved EC2/EKS would be more economical, factoring in operational costs.
Understanding API Gateway's performance characteristics and limits is essential for capacity planning.
| Limit | REST API | HTTP API | Adjustable |
|---|---|---|---|
| Requests/second (account) | 10,000 | 10,000 | Yes (quota increase) |
| Requests/second (per route) | 10,000 | 10,000 | Yes |
| Concurrent connections (WebSocket) | N/A | N/A | Varies by region |
| Integration timeout | 29 seconds | 30 seconds | No |
| Payload size | 10 MB | 10 MB | No |
| Response size (Lambda) | 6 MB | 6 MB | No (Lambda limit) |
| URL length | 8 KB | 8 KB | No |
| Headers total size | 10 KB | 10 KB | No |
Added Latency (Gateway Overhead):
End-to-end Components:
Total Latency = Gateway Overhead + Lambda Cold Start (if any)
+ Lambda Execution + Backend Calls
Cold Start Mitigation:
API Gateway's hard 29-30 second timeout cannot be increased. For long-running operations, return immediately with a job ID and implement polling or WebSocket notifications. Alternatively, use Step Functions for orchestration with longer timeouts.
API Gateway should be fully defined in code (CloudFormation, SAM, CDK, Terraform):
123456789101112131415161718192021222324252627282930313233
import * as cdk from 'aws-cdk-lib';import * as apigateway from 'aws-cdk-lib/aws-apigateway';import * as lambda from 'aws-cdk-lib/aws-lambda'; export class ApiStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); const handler = new lambda.Function(this, 'Handler', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.handler', code: lambda.Code.fromAsset('lambda'), }); const api = new apigateway.RestApi(this, 'Api', { restApiName: 'MyAPI', deployOptions: { stageName: 'prod', throttlingRateLimit: 1000, throttlingBurstLimit: 500, cachingEnabled: true, cacheTtl: cdk.Duration.minutes(5), metricsEnabled: true, loggingLevel: apigateway.MethodLoggingLevel.INFO, }, }); const users = api.root.addResource('users'); users.addMethod('GET', new apigateway.LambdaIntegration(handler), { authorizationType: apigateway.AuthorizationType.IAM, }); }}Set CloudWatch alarms on: 5XXError rate > 1%, Latency P99 > SLA threshold, Count anomaly detection. Enable X-Ray sampling at 10% minimum for production debugging. Access logs should include requestId, ip, caller, responseLength, and latency.
AWS API Gateway trades flexibility for operational simplicity. You can't SSH into an instance, install custom modules, or optimize at the NGINX level. In return, you never patch, scale, or failover the gateway—AWS handles it. For teams prioritizing velocity over control, this trade-off is compelling.
What's Next:
Having explored a managed, cloud-native API Gateway, we'll next examine Ambassador—a Kubernetes-native API Gateway built on Envoy that represents a third architectural philosophy: gateway as Kubernetes-native ingress.
You now understand AWS API Gateway's architecture, types, integration patterns, cost model, and decision criteria. You can evaluate it against self-hosted alternatives and design serverless API architectures effectively.