Skip to main content

Skillber v1.0 is here!

Learn more

API Gateway & Step Functions

Checking access...

Amazon API Gateway creates, publishes, and secures APIs at any scale. AWS Step Functions coordinates multiple AWS services into serverless workflows.

API Gateway — API Types

TypeFeaturesUse Case
REST APIFull feature set — usage plans, API keys, caching, transformations, WAFProduction APIs requiring granular control
HTTP APISimplified, lower cost, lower latency (~50% cheaper, ~30% faster)Modern APIs, Lambda proxies, simpler auth
WebSocket APIBidirectional communication, persistent connectionsReal-time apps, chat, streaming data

REST API with Lambda Integration

resource "aws_api_gateway_rest_api" "api" {
name = "my-api"
description = "Serverless API"
}
resource "aws_api_gateway_resource" "items" {
rest_api_id = aws_api_gateway_rest_api.api.id
parent_id = aws_api_gateway_rest_api.api.root_resource_id
path_part = "items"
}
resource "aws_api_gateway_method" "get_items" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.items.id
http_method = "GET"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "get_items_lambda" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.items.id
http_method = aws_api_gateway_method.get_items.http_method
type = "AWS_PROXY"
uri = aws_lambda_function.get_items.invoke_arn
}
# Lambda handler for API Gateway
import json
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Items')
def lambda_handler(event, context):
try:
response = table.scan()
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
'body': json.dumps(response['Items'])
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)})
}

Usage Plans and API Keys

Protect your API with throttling and quota limits:

resource "aws_api_gateway_usage_plan" "basic" {
name = "basic-plan"
api_stages {
api_id = aws_api_gateway_rest_api.api.id
stage = "prod"
}
throttle_settings {
burst_limit = 100
rate_limit = 50
}
quota_settings {
limit = 10000
period = "MONTH"
}
}
resource "aws_api_gateway_api_key" "client1" {
name = "client-1-key"
}
resource "aws_api_gateway_usage_plan_key" "client1_plan" {
key_id = aws_api_gateway_api_key.client1.id
key_type = "API_KEY"
usage_plan_id = aws_api_gateway_usage_plan.basic.id
}
Terminal window
# Test with the API key
curl -H "x-api-key: $(aws apigateway get-api-key --api-key <key-id> --include-value --query 'value' --output text)" \
https://api-id.execute-api.us-east-1.amazonaws.com/prod/items

Step Functions — State Machines

Step Functions coordinate Lambda, ECS, SQS, DynamoDB, and other services into workflows defined as JSON state machines:

{
"Comment": "Order processing workflow",
"StartAt": "ValidateOrder",
"States": {
"ValidateOrder": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:validate-order",
"Next": "ProcessPayment"
},
"ProcessPayment": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:process-payment",
"Next": "CheckInventory",
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 5,
"MaxAttempts": 3,
"BackoffRate": 2
}
],
"Catch": [
{
"ErrorEquals": ["PaymentFailed"],
"Next": "CancelOrder"
}
]
},
"CheckInventory": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:check-inventory",
"Next": "ShipOrder"
},
"ShipOrder": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:ship-order",
"End": true
},
"CancelOrder": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:cancel-order",
"End": true
}
}
}

State Types

State TypePurposeExample
TaskExecute a unit of work (Lambda, ECS, SQS, etc.)"Resource": "arn:aws:lambda:..."
ChoiceBranch based on input valuesSwitch on order status
ParallelExecute branches concurrentlyProcess payment + check inventory simultaneously
MapIterate over a list of itemsProcess each line item in an order
WaitPause execution for a duration or until a timestampDelay before sending reminder
PassPass input to output, inject dataTransform payload format
Succeed/FailTerminal statesMark workflow as successful or failed
resource "aws_sfn_state_machine" "order_workflow" {
name = "order-processing-workflow"
role_arn = aws_iam_role.step_functions.arn
definition = jsonencode({
Comment = "Order processing workflow"
StartAt = "ValidateOrder"
States = {
ValidateOrder = {
Type = "Task"
Resource = aws_lambda_function.validate_order.arn
Next = "ProcessPayment"
}
ProcessPayment = {
Type = "Task"
Resource = aws_lambda_function.process_payment.arn
Next = "NotifyCustomer"
Retry = [
{
ErrorEquals = ["States.ALL"]
IntervalSeconds = 5
MaxAttempts = 3
BackoffRate = 2
}
]
}
NotifyCustomer = {
Type = "Task"
Resource = aws_sns_topic.order_notifications.arn
End = true
}
}
})
}

Standard vs Express Workflows

Standard workflows have exactly-once execution, cost per state transition, and 1-year max duration — ideal for long-running, auditable workflows. Express workflows have at-least-once execution, cost per execution/duration, and 5-minute max duration — ideal for high-volume, short-lived tasks.

Key Takeaways

  • REST APIs are full-featured (usage plans, caching, WAF); HTTP APIs are simpler, cheaper, faster (~50% less cost); WebSocket APIs support real-time bidirectional communication
  • Usage plans enforce throttling (burst/rate) and quotas (daily/weekly/monthly) per API key — essential for protecting backend services from abuse
  • Step Functions define workflows as JSON state machines with Task (execute service), Choice (branch), Parallel (concurrent), Map (iterate), Wait (delay), Pass (transform), Succeed/Fail (terminal) states
  • Retry with exponential backoff handles transient failures; Catch with error routing handles business logic failures
  • Standard workflows (exactly-once, long-running, auditable) vs Express workflows (at-least-once, high-volume, short-lived under 5 min)