AWS API Gateway
Fully managed API management service. Supports REST and WebSocket APIs, integrates auto-scaling, monitoring, and security features. Serverless compatible.
Server
AWS API Gateway
Overview
AWS API Gateway is a fully managed service that enables developers to create, publish, maintain, monitor, and secure APIs at any scale, serving as the "front door" for applications to access data, business logic, or functionality from backend services. As a comprehensive API management platform, AWS API Gateway supports REST APIs, HTTP APIs, and WebSocket APIs, providing automatic scaling, built-in security features, and seamless integration with the broader AWS ecosystem. Designed for serverless architectures and cloud-native applications, API Gateway eliminates the operational overhead of managing API infrastructure while offering enterprise-grade features for authentication, authorization, traffic management, and monitoring.
Details
AWS API Gateway 2025 edition continues to evolve as a cornerstone service for modern application architectures, particularly in serverless and microservices environments. The platform offers three distinct API types: REST APIs for full-featured API management, HTTP APIs for cost-effective serverless workloads (up to 71% cheaper), and WebSocket APIs for real-time bidirectional communication. Built on AWS's global infrastructure, API Gateway provides automatic scaling to handle any traffic volume, regional and edge-optimized endpoints for low latency, and deep integration with AWS services like Lambda, DynamoDB, SNS, and Step Functions. The service includes comprehensive security features including IAM integration, custom authorizers, API keys, usage plans, and AWS WAF integration for advanced threat protection.
Key Features
- Multiple API Types: REST, HTTP, and WebSocket APIs for different use cases
- Serverless Integration: Native integration with AWS Lambda and serverless architectures
- Automatic Scaling: Handles traffic spikes without manual intervention or capacity planning
- Security and Authorization: IAM, Cognito, Lambda authorizers, and API key management
- Traffic Management: Throttling, caching, CORS support, and request/response transformation
- Monitoring and Analytics: CloudWatch integration, X-Ray tracing, and access logging
Advantages and Disadvantages
Advantages
- Fully managed service eliminating infrastructure management and operational overhead
- Automatic scaling and high availability with AWS global infrastructure and SLA guarantees
- Pay-per-use pricing model with no upfront costs or minimum fees for cost-effective scaling
- Seamless AWS ecosystem integration enabling easy connection to Lambda, DynamoDB, and other services
- Enterprise-grade security features with IAM, WAF, and custom authentication mechanisms
- Comprehensive monitoring and analytics through CloudWatch and X-Ray for operational insights
Disadvantages
- AWS vendor lock-in limiting portability to other cloud providers or on-premises deployments
- Cost accumulation with high-volume APIs potentially becoming expensive at scale
- Limited customization compared to self-hosted solutions with restricted configuration options
- Cold start latency issues when integrating with Lambda functions affecting response times
- Regional limitations and compliance considerations for data residency requirements
- Complex pricing model with multiple factors making cost prediction challenging for complex scenarios
Reference Links
Code Examples
REST API Creation and Deployment
# Create REST API using AWS CLI
aws apigateway create-rest-api \
--name "ProductAPI" \
--description "REST API for product management" \
--endpoint-configuration types=REGIONAL
# Get API ID from response
API_ID="your-api-id"
# Get root resource ID
ROOT_ID=$(aws apigateway get-resources \
--rest-api-id $API_ID \
--query 'items[?path==`/`].id' \
--output text)
# Create resource
aws apigateway create-resource \
--rest-api-id $API_ID \
--parent-id $ROOT_ID \
--path-part "products"
# Get products resource ID
PRODUCTS_ID=$(aws apigateway get-resources \
--rest-api-id $API_ID \
--query 'items[?path==`/products`].id' \
--output text)
# Create GET method
aws apigateway put-method \
--rest-api-id $API_ID \
--resource-id $PRODUCTS_ID \
--http-method GET \
--authorization-type "AWS_IAM"
CloudFormation Template for REST API
# template.yml - Complete REST API with Lambda integration
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
StageName:
Type: String
Default: prod
Description: API Gateway stage name
Resources:
# Lambda function
ProductsFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: products.handler
Runtime: python3.9
Environment:
Variables:
TABLE_NAME: !Ref ProductsTable
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref ProductsTable
# DynamoDB table
ProductsTable:
Type: AWS::DynamoDB::Table
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
# API Gateway REST API
ProductsApi:
Type: AWS::Serverless::Api
Properties:
StageName: !Ref StageName
Cors:
AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
AllowOrigin: "'*'"
Auth:
DefaultAuthorizer: AWS_IAM
GatewayResponses:
DEFAULT_4XX:
ResponseTemplates:
"application/json": '{"message":$context.error.messageString}'
DEFAULT_5XX:
ResponseTemplates:
"application/json": '{"message":"Internal server error"}'
# API Gateway Resource
ProductsResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref ProductsApi
ParentId: !GetAtt ProductsApi.RootResourceId
PathPart: products
# GET method
GetProductsMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ProductsApi
ResourceId: !Ref ProductsResource
HttpMethod: GET
AuthorizationType: AWS_IAM
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ProductsFunction.Arn}/invocations'
MethodResponses:
- StatusCode: 200
ResponseModels:
application/json: Empty
# POST method
CreateProductMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ProductsApi
ResourceId: !Ref ProductsResource
HttpMethod: POST
AuthorizationType: AWS_IAM
RequestValidatorId: !Ref RequestValidator
RequestModels:
application/json: !Ref ProductModel
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ProductsFunction.Arn}/invocations'
# Request validator
RequestValidator:
Type: AWS::ApiGateway::RequestValidator
Properties:
RestApiId: !Ref ProductsApi
ValidateRequestBody: true
ValidateRequestParameters: true
# Model for request validation
ProductModel:
Type: AWS::ApiGateway::Model
Properties:
RestApiId: !Ref ProductsApi
ContentType: application/json
Schema:
$schema: http://json-schema.org/draft-04/schema#
type: object
properties:
name:
type: string
minLength: 1
price:
type: number
minimum: 0
description:
type: string
required:
- name
- price
Outputs:
ApiUrl:
Description: "API Gateway endpoint URL"
Value: !Sub "https://${ProductsApi}.execute-api.${AWS::Region}.amazonaws.com/${StageName}"
HTTP API (Serverless-optimized)
# http-api.yml - Cost-effective HTTP API
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
# HTTP API (cheaper alternative to REST API)
HttpApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: prod
CorsConfiguration:
AllowOrigins:
- "https://myapp.example.com"
AllowHeaders:
- Content-Type
- Authorization
AllowMethods:
- GET
- POST
- PUT
- DELETE
MaxAge: 600
AllowCredentials: true
Auth:
Authorizers:
JwtAuthorizer:
JwtConfiguration:
issuer: "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_example"
audience:
- "client-id-1"
- "client-id-2"
IdentitySource: "$request.header.Authorization"
DefaultAuthorizer: JwtAuthorizer
# Lambda function for HTTP API
SimpleFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: app.lambda_handler
Runtime: python3.9
Events:
GetProducts:
Type: HttpApi
Properties:
ApiId: !Ref HttpApi
Method: GET
Path: /products
CreateProduct:
Type: HttpApi
Properties:
ApiId: !Ref HttpApi
Method: POST
Path: /products
WebSocket API Implementation
# websocket-api.yml - Real-time WebSocket API
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
# WebSocket API
ChatApi:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: ChatWebSocketAPI
ProtocolType: WEBSOCKET
RouteSelectionExpression: "$request.body.action"
# Connection handler
ConnectFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: websocket/
Handler: connect.handler
Runtime: python3.9
Environment:
Variables:
TABLE_NAME: !Ref ConnectionsTable
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref ConnectionsTable
# Disconnect handler
DisconnectFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: websocket/
Handler: disconnect.handler
Runtime: python3.9
Environment:
Variables:
TABLE_NAME: !Ref ConnectionsTable
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref ConnectionsTable
# Message handler
MessageFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: websocket/
Handler: message.handler
Runtime: python3.9
Environment:
Variables:
TABLE_NAME: !Ref ConnectionsTable
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref ConnectionsTable
- Statement:
- Effect: Allow
Action:
- 'execute-api:ManageConnections'
Resource: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ChatApi}/*'
# DynamoDB table for connections
ConnectionsTable:
Type: AWS::DynamoDB::Table
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: connectionId
AttributeType: S
KeySchema:
- AttributeName: connectionId
KeyType: HASH
# WebSocket routes
ConnectRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref ChatApi
RouteKey: $connect
AuthorizationType: NONE
OperationName: ConnectRoute
Target: !Join
- '/'
- - 'integrations'
- !Ref ConnectInteg
DisconnectRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref ChatApi
RouteKey: $disconnect
AuthorizationType: NONE
OperationName: DisconnectRoute
Target: !Join
- '/'
- - 'integrations'
- !Ref DisconnectInteg
MessageRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref ChatApi
RouteKey: sendmessage
AuthorizationType: NONE
OperationName: MessageRoute
Target: !Join
- '/'
- - 'integrations'
- !Ref MessageInteg
# Integrations
ConnectInteg:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref ChatApi
Description: Connect Integration
IntegrationType: AWS_PROXY
IntegrationUri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ConnectFunction.Arn}/invocations'
DisconnectInteg:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref ChatApi
Description: Disconnect Integration
IntegrationType: AWS_PROXY
IntegrationUri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DisconnectFunction.Arn}/invocations'
MessageInteg:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref ChatApi
Description: Message Integration
IntegrationType: AWS_PROXY
IntegrationUri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MessageFunction.Arn}/invocations'
# Deployment and Stage
Deployment:
Type: AWS::ApiGatewayV2::Deployment
DependsOn:
- ConnectRoute
- DisconnectRoute
- MessageRoute
Properties:
ApiId: !Ref ChatApi
Stage:
Type: AWS::ApiGatewayV2::Stage
Properties:
StageName: prod
Description: Production Stage
DeploymentId: !Ref Deployment
ApiId: !Ref ChatApi
Outputs:
WebSocketURI:
Description: "WebSocket API URI"
Value: !Sub "wss://${ChatApi}.execute-api.${AWS::Region}.amazonaws.com/prod"
Lambda Authorizer Implementation
# authorizer.py - Custom Lambda authorizer
import json
import jwt
from jwt.exceptions import InvalidTokenError
def lambda_handler(event, context):
"""
Custom authorizer for API Gateway
"""
token = event['authorizationToken']
method_arn = event['methodArn']
try:
# Remove 'Bearer ' prefix
if token.startswith('Bearer '):
token = token[7:]
# Verify JWT token (replace with your secret/public key)
payload = jwt.decode(
token,
'your-secret-key',
algorithms=['HS256']
)
principal_id = payload.get('sub', 'user')
# Generate policy
policy = generate_policy(principal_id, 'Allow', method_arn)
# Add context information
policy['context'] = {
'userId': payload.get('sub'),
'email': payload.get('email'),
'role': payload.get('role', 'user')
}
return policy
except InvalidTokenError:
# Return 401 Unauthorized
raise Exception('Unauthorized')
except Exception as e:
print(f"Error: {str(e)}")
raise Exception('Unauthorized')
def generate_policy(principal_id, effect, resource):
"""
Generate IAM policy for API Gateway
"""
auth_response = {
'principalId': principal_id
}
if effect and resource:
policy_document = {
'Version': '2012-10-17',
'Statement': [
{
'Action': 'execute-api:Invoke',
'Effect': effect,
'Resource': resource
}
]
}
auth_response['policyDocument'] = policy_document
return auth_response
Advanced Request/Response Transformation
# API Gateway with VTL transformations
ProductDetailMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ProductsApi
ResourceId: !Ref ProductDetailResource
HttpMethod: GET
AuthorizationType: AWS_IAM
RequestParameters:
method.request.path.id: true
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:dynamodb:action/GetItem'
Credentials: !GetAtt ApiGatewayRole.Arn
RequestTemplates:
application/json: |
{
"TableName": "${ProductsTable}",
"Key": {
"id": {
"S": "$input.params('id')"
}
}
}
ResponseTemplates:
application/json: |
#set($item = $input.path('$.Item'))
#if($item.toString() != "{}")
{
"id": "$item.id.S",
"name": "$item.name.S",
"price": $item.price.N,
"description": "$item.description.S",
"createdAt": "$item.createdAt.S"
}
#else
#set($context.responseOverride.status = 404)
{
"error": "Product not found"
}
#end
IntegrationResponses:
- StatusCode: 200
- StatusCode: 404
SelectionPattern: '.*"error".*'
MethodResponses:
- StatusCode: 200
ResponseModels:
application/json: !Ref ProductModel
- StatusCode: 404
ResponseModels:
application/json: !Ref ErrorModel
Monitoring and Logging Setup
# CloudWatch and X-Ray configuration
ApiGatewayAccount:
Type: AWS::ApiGateway::Account
Properties:
CloudWatchRoleArn: !GetAtt CloudWatchRole.Arn
CloudWatchRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: apigateway.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CloudWatchPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:DescribeLogGroups
- logs:DescribeLogStreams
- logs:PutLogEvents
- logs:GetLogEvents
- logs:FilterLogEvents
Resource: "*"
# API Gateway stage with logging
ApiStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref ProductsApi
DeploymentId: !Ref ApiDeployment
StageName: prod
TracingConfig:
TracingEnabled: true
AccessLogSetting:
DestinationArn: !Sub '${ApiLogGroup.Arn}'
Format: |
{
"requestId": "$context.requestId",
"ip": "$context.identity.sourceIp",
"user": "$context.identity.user",
"requestTime": "$context.requestTime",
"httpMethod": "$context.httpMethod",
"resourcePath": "$context.resourcePath",
"status": "$context.status",
"protocol": "$context.protocol",
"responseLength": "$context.responseLength",
"responseTime": "$context.responseTime",
"error": "$context.error.message",
"integrationError": "$context.integration.error"
}
MethodSettings:
- ResourcePath: /*
HttpMethod: "*"
LoggingLevel: INFO
DataTraceEnabled: true
MetricsEnabled: true
ApiLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/aws/apigateway/${ProductsApi}'
RetentionInDays: 14
Usage Plans and API Keys
# API Key and Usage Plan configuration
ApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Name: ProductAPIKey
Description: API Key for Products API
Enabled: true
GenerateDistinctId: true
UsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
UsagePlanName: ProductAPIUsagePlan
Description: Usage plan for Products API
ApiStages:
- ApiId: !Ref ProductsApi
Stage: prod
Throttle:
RateLimit: 100
BurstLimit: 200
Quota:
Limit: 10000
Period: MONTH
UsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
Properties:
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref UsagePlan