Developing a microservice on Lambda and getting error 502 — integration timeouts. Or a client complains about response speed while CloudWatch logs show delays up to 10 seconds. Most likely, the issue is with API Gateway configuration: incorrect timeout, missing caching, or wrong authorizer type. Over 5 years of working with AWS, we've configured more than 50 API Gateways — from simple REST proxies to multi-region gateways with Cognito and custom authorizers. Recently, on one project, a wrong timeout configuration caused endpoint failure under peak load. After switching from HTTP to REST API and enabling caching, latency dropped by 40%, and infrastructure costs decreased by 30%. Order a free consultation — we'll help you save up to 30% on your monthly API Gateway expenses.
We solve these problems: incorrect Lambda integration (N+1 DynamoDB queries due to poor design), lack of throttling leading to backend overload, and wrong API type selection — REST instead of HTTP, causing you to pay 3.5 times more. Proper API Gateway configuration can reduce latency by 40% and prevent downtime. Optimal caching setup cuts latency in half.
How to Choose Between REST API and HTTP API?
| Feature | REST API | HTTP API |
|---|---|---|
| Lambda integration | + | + |
| JWT authorizer | + | + |
| Custom authorizer | + | + |
| Usage plans / API keys | + | — |
| Request/Response mapping | + | — |
| WAF integration | + | — |
| Private endpoints | + | — |
| Price (per million requests) | $3.50 | $1.00 |
HTTP API suits simple backend->Lambda proxies. REST API is needed for complex request transformation and throttling by API keys. If you're just starting out, choose HTTP — it's 3.5 times cheaper. A proper choice can save up to 20% of your infrastructure budget.
How to Reduce API Gateway Costs?
Choosing the right API type is just the first step. Enabling caching at the gateway level reduces the number of Lambda invocations, directly impacting cost. Under high load, switching from HTTP to REST with caching can lower costs by 30–50%. Also use Terraform for automation: eliminating manual errors reduces costly incidents. We'll assess your scenario and propose the optimal configuration — contact us for details.
Why Use Terraform for API Gateway?
Terraform allows versioning infrastructure as code, avoiding manual configuration errors and reproducing environments in minutes. Below is a typical REST API configuration with Cognito authorization that we use in every project.
# main.tf
resource "aws_api_gateway_rest_api" "main" {
name = "myapp-api"
description = "Main application API"
endpoint_configuration {
types = ["REGIONAL"]
}
}
resource "aws_api_gateway_resource" "users" {
rest_api_id = aws_api_gateway_rest_api.main.id
parent_id = aws_api_gateway_rest_api.main.root_resource_id
path_part = "users"
}
resource "aws_api_gateway_method" "users_get" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.users.id
http_method = "GET"
authorization = "COGNITO_USER_POOLS"
authorizer_id = aws_api_gateway_authorizer.cognito.id
request_parameters = {
"method.request.querystring.page" = false
"method.request.querystring.limit" = false
}
}
resource "aws_api_gateway_integration" "users_get" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.users.id
http_method = aws_api_gateway_method.users_get.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = aws_lambda_function.users_handler.invoke_arn
}
How to Choose the Authorization Type?
Cognito is suitable for JWT authentication with social networks or LDAP. Lambda authorizer is needed for integration with an external IdP or complex logic (e.g., IP-based access control). Choose Cognito for standard scenarios, Lambda for flexibility.
Cognito Authorizer
resource "aws_api_gateway_authorizer" "cognito" {
name = "cognito-authorizer"
rest_api_id = aws_api_gateway_rest_api.main.id
type = "COGNITO_USER_POOLS"
provider_arns = [aws_cognito_user_pool.main.arn]
identity_source = "method.request.header.Authorization"
}
Lambda Authorizer (Custom Authentication)
resource "aws_api_gateway_authorizer" "lambda" {
name = "lambda-authorizer"
rest_api_id = aws_api_gateway_rest_api.main.id
authorizer_uri = aws_lambda_function.authorizer.invoke_arn
authorizer_result_ttl_in_seconds = 300
type = "TOKEN"
identity_source = "method.request.header.Authorization"
}
Usage Plans and API Keys
resource "aws_api_gateway_usage_plan" "standard" {
name = "standard-plan"
api_stages {
api_id = aws_api_gateway_rest_api.main.id
stage = aws_api_gateway_stage.prod.stage_name
}
throttle_settings {
burst_limit = 100
rate_limit = 50
}
quota_settings {
limit = 10000
period = "DAY"
}
}
resource "aws_api_gateway_api_key" "partner_app" {
name = "partner-app-key"
}
resource "aws_api_gateway_usage_plan_key" "partner" {
key_id = aws_api_gateway_api_key.partner_app.id
key_type = "API_KEY"
usage_plan_id = aws_api_gateway_usage_plan.standard.id
}
Stage, Logging, and Deployment
resource "aws_api_gateway_deployment" "main" {
rest_api_id = aws_api_gateway_rest_api.main.id
triggers = {
redeployment = sha1(jsonencode([
aws_api_gateway_resource.users.id,
aws_api_gateway_method.users_get.id,
aws_api_gateway_integration.users_get.id,
]))
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_api_gateway_stage" "prod" {
deployment_id = aws_api_gateway_deployment.main.id
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = "prod"
access_log_settings {
destination_arn = aws_cloudwatch_log_group.api_gateway.arn
format = jsonencode({
requestId = "$context.requestId"
sourceIp = "$context.identity.sourceIp"
requestTime = "$context.requestTime"
httpMethod = "$context.httpMethod"
routeKey = "$context.routeKey"
status = "$context.status"
responseLength = "$context.responseLength"
latency = "$context.responseLatency"
})
}
}
resource "aws_api_gateway_method_settings" "prod" {
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = aws_api_gateway_stage.prod.stage_name
method_path = "*/*"
settings {
throttling_burst_limit = 500
throttling_rate_limit = 200
logging_level = "INFO"
metrics_enabled = true
}
}
How to Set Up Monitoring and Alerts?
- Enable
metrics_enabled = truein the stage settings. - Define key metrics: 4XXError, 5XXError, Latency, Count.
- Create CloudWatch Alarms based on thresholds (see table below).
- Configure SNS notifications for alerts.
| Metric | Description | Alert Threshold |
|---|---|---|
| 4XXError | Number of client errors | > 5% of requests |
| 5XXError | Number of server errors | > 1% of requests |
| Latency | Average response latency | > 1000 ms |
| Count | Number of requests | > 1000/min |
This approach allows timely reaction to issues and maintains SLA.
What's Included in the Work
| Stage | Duration | Result |
|---|---|---|
| Current architecture audit | 1 day | Optimization plan |
| API design | 1–2 days | API schema, authorization choice |
| Terraform scripts | 2–3 days | Reproducible infrastructure |
| Integration with Lambda/DB | 1–2 days | Working endpoints |
| Monitoring setup | 0.5 day | CloudWatch dashboard and alerts |
| Deployment and documentation | 1 day | Staging + documentation |
Delivery Timelines
Setting up a REST API with one authorizer and usage plan takes 3–5 business days. If a custom domain or complex transformation is required, up to 7 days. Exact timelines are assessed after a free audit of your project.
End-to-end API Gateway setup can save up to 30% of development costs by using infrastructure as code. Our team of certified AWS engineers has 5+ years of experience and 50+ successful API Gateway projects. Contact us for a free consultation — we'll prepare a custom proposal and calculate your real savings. Get a project assessment today.







