AWS API Gateway ile REST API Oluşturma Rehberi

AWS’de bir REST API kurmak kulağa basit gelir, ama API Gateway’in tüm özelliklerini, entegrasyonlarını ve güvenlik katmanlarını doğru yapılandırmak ciddi bir iş. Yanlış bir ayar, ya güvenlik açığı bırakır ya da beklenmedik maliyetlere yol açar. Bu yazıda, gerçek dünya senaryoları üzerinden AWS API Gateway ile REST API oluşturmayı, yapılandırmayı ve production ortamına almayı adım adım ele alacağız.

API Gateway Nedir ve Ne Zaman Kullanmalısınız?

API Gateway, AWS’nin tam yönetilen bir API yönetim servisidir. Arkadaki Lambda fonksiyonlarınıza, EC2 instance’larınıza ya da herhangi bir HTTP endpoint’inize trafik yönlendiren bir kapı görevi görür. Sadece yönlendirme değil; kimlik doğrulama, rate limiting, caching, logging ve monitoring gibi kritik özellikleri de üstlenir.

Kullanım senaryoları:

  • Mikroservis mimarisinde servisleri dışarıya açmak
  • Lambda fonksiyonlarını HTTP üzerinden erişilebilir kılmak
  • Legacy backend sistemleri önüne modern bir API katmanı eklemek
  • Mobile ve web uygulamalar için backend as a service (BaaS) mimarisi kurmak

REST API mi, HTTP API mi yoksa WebSocket API mi kullanacağınızı da seçmeniz gerekir. Bu yazıda REST API üzerine yoğunlaşacağız çünkü en fazla özelliği sunuyor ve enterprise senaryolarda hala birinci tercih.

Ortam Hazırlığı

AWS CLI kurulu ve yapılandırılmış olmalı. Eğer yoksa önce bunu halledelim.

# AWS CLI kurulumu (Linux)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Kimlik bilgilerini yapılandır
aws configure
# AWS Access Key ID: [sizin key'iniz]
# AWS Secret Access Key: [sizin secret'ınız]
# Default region name: eu-west-1
# Default output format: json

# Doğrulama
aws sts get-caller-identity

Örnek senaryomuz şu: Bir e-ticaret uygulaması için ürün yönetim API’si oluşturacağız. GET, POST, PUT ve DELETE metodları olacak, arkada Lambda fonksiyonları çalışacak ve Cognito ile kimlik doğrulaması yapacağız.

Lambda Fonksiyonlarının Hazırlanması

API Gateway bir proxy olduğu için arkasındaki Lambda fonksiyonlarını önce hazırlamamız gerekiyor.

# Önce IAM rolü oluşturalım
aws iam create-role 
  --role-name lambda-api-role 
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "Service": "lambda.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }
    ]
  }'

# Temel Lambda politikasını ekle
aws iam attach-role-policy 
  --role-name lambda-api-role 
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# Rol ARN'ını not al
aws iam get-role --role-name lambda-api-role --query 'Role.Arn' --output text

Şimdi basit bir Lambda fonksiyonu oluşturalım:

# Lambda fonksiyon kodunu hazırla
cat > products_handler.py << 'EOF'
import json
import boto3

def handler(event, context):
    http_method = event.get('httpMethod', '')
    path = event.get('path', '')
    
    if http_method == 'GET' and path == '/products':
        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*'
            },
            'body': json.dumps({
                'products': [
                    {'id': '1', 'name': 'Laptop', 'price': 1299.99},
                    {'id': '2', 'name': 'Mouse', 'price': 29.99}
                ]
            })
        }
    elif http_method == 'POST' and path == '/products':
        body = json.loads(event.get('body', '{}'))
        return {
            'statusCode': 201,
            'headers': {'Content-Type': 'application/json'},
            'body': json.dumps({'message': 'Ürün oluşturuldu', 'data': body})
        }
    else:
        return {
            'statusCode': 404,
            'body': json.dumps({'message': 'Endpoint bulunamadı'})
        }
EOF

# Zip'le ve Lambda'ya yükle
zip products_handler.zip products_handler.py

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION="eu-west-1"

aws lambda create-function 
  --function-name products-api-handler 
  --runtime python3.11 
  --role arn:aws:iam::${ACCOUNT_ID}:role/lambda-api-role 
  --handler products_handler.handler 
  --zip-file fileb://products_handler.zip 
  --timeout 30 
  --memory-size 256 
  --region ${REGION}

REST API Oluşturma

Şimdi asıl işe gelelim. API Gateway REST API’yi oluşturuyoruz.

# REST API oluştur
API_ID=$(aws apigateway create-rest-api 
  --name "products-api" 
  --description "E-ticaret ürün yönetim API'si" 
  --endpoint-configuration types=REGIONAL 
  --query 'id' 
  --output text 
  --region ${REGION})

echo "API ID: ${API_ID}"

# Root resource ID'yi al (/ path'ı)
ROOT_RESOURCE_ID=$(aws apigateway get-resources 
  --rest-api-id ${API_ID} 
  --query 'items[0].id' 
  --output text 
  --region ${REGION})

echo "Root Resource ID: ${ROOT_RESOURCE_ID}"

# /products resource'u oluştur
PRODUCTS_RESOURCE_ID=$(aws apigateway create-resource 
  --rest-api-id ${API_ID} 
  --parent-id ${ROOT_RESOURCE_ID} 
  --path-part "products" 
  --query 'id' 
  --output text 
  --region ${REGION})

echo "Products Resource ID: ${PRODUCTS_RESOURCE_ID}"

# /products/{productId} resource'u oluştur (tekil ürün için)
PRODUCT_RESOURCE_ID=$(aws apigateway create-resource 
  --rest-api-id ${API_ID} 
  --parent-id ${PRODUCTS_RESOURCE_ID} 
  --path-part "{productId}" 
  --query 'id' 
  --output text 
  --region ${REGION})

echo "Product Resource ID: ${PRODUCT_RESOURCE_ID}"

HTTP Metodlarını ve Lambda Entegrasyonunu Yapılandırma

Resource’ları oluşturduktan sonra HTTP metodlarını tanımlamalı ve Lambda ile entegre etmeliyiz.

# GET /products metodu oluştur
aws apigateway put-method 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method GET 
  --authorization-type NONE 
  --region ${REGION}

# GET /products için Lambda entegrasyonu
aws apigateway put-integration 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method GET 
  --type AWS_PROXY 
  --integration-http-method POST 
  --uri "arn:aws:apigateway:${REGION}:lambda:path/2015-03-31/functions/arn:aws:lambda:${REGION}:${ACCOUNT_ID}:function:products-api-handler/invocations" 
  --region ${REGION}

# POST /products metodu oluştur
aws apigateway put-method 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method POST 
  --authorization-type NONE 
  --region ${REGION}

# POST /products için Lambda entegrasyonu
aws apigateway put-integration 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method POST 
  --type AWS_PROXY 
  --integration-http-method POST 
  --uri "arn:aws:apigateway:${REGION}:lambda:path/2015-03-31/functions/arn:aws:lambda:${REGION}:${ACCOUNT_ID}:function:products-api-handler/invocations" 
  --region ${REGION}

# Lambda'ya API Gateway'den çağrı yetkisi ver
aws lambda add-permission 
  --function-name products-api-handler 
  --statement-id apigateway-get-products 
  --action lambda:InvokeFunction 
  --principal apigateway.amazonaws.com 
  --source-arn "arn:aws:execute-api:${REGION}:${ACCOUNT_ID}:${API_ID}/*/GET/products" 
  --region ${REGION}

aws lambda add-permission 
  --function-name products-api-handler 
  --statement-id apigateway-post-products 
  --action lambda:InvokeFunction 
  --principal apigateway.amazonaws.com 
  --source-arn "arn:aws:execute-api:${REGION}:${ACCOUNT_ID}:${API_ID}/*/POST/products" 
  --region ${REGION}

Önemli not: AWS_PROXY tipi entegrasyon kullandığınızda, API Gateway request’i olduğu gibi Lambda’ya iletir ve Lambda’nın döndürdüğü response’u da olduğu gibi client’a gönderir. Bu en yaygın ve esnek yaklaşımdır.

Stage Oluşturma ve Deploy Etme

API’yi erişilebilir kılmak için bir stage’e deploy etmemiz gerekiyor.

# Önce bir deployment oluştur
DEPLOYMENT_ID=$(aws apigateway create-deployment 
  --rest-api-id ${API_ID} 
  --description "İlk deployment" 
  --query 'id' 
  --output text 
  --region ${REGION})

echo "Deployment ID: ${DEPLOYMENT_ID}"

# Production stage oluştur ve deploy et
aws apigateway create-stage 
  --rest-api-id ${API_ID} 
  --stage-name prod 
  --deployment-id ${DEPLOYMENT_ID} 
  --description "Production ortamı" 
  --variables '{"environment":"production"}' 
  --region ${REGION}

# API URL'ini oluştur ve test et
API_URL="https://${API_ID}.execute-api.${REGION}.amazonaws.com/prod"
echo "API URL: ${API_URL}"

# Test et
curl -X GET "${API_URL}/products" 
  -H "Content-Type: application/json"

Throttling ve Usage Plan Yapılandırması

Production’da rate limiting olmadan API açmak ciddi risk. Hem maliyeti kontrol altına almak hem de kötüye kullanımı önlemek için usage plan ve API key yapılandırması şart.

# API key oluştur
API_KEY_ID=$(aws apigateway create-api-key 
  --name "products-api-key-v1" 
  --description "Ürün API'si için birincil key" 
  --enabled 
  --query 'id' 
  --output text 
  --region ${REGION})

echo "API Key ID: ${API_KEY_ID}"

# API key değerini al
aws apigateway get-api-key 
  --api-key ${API_KEY_ID} 
  --include-value 
  --query 'value' 
  --output text 
  --region ${REGION}

# Usage plan oluştur (throttling ve quota ayarları)
USAGE_PLAN_ID=$(aws apigateway create-usage-plan 
  --name "products-api-standard-plan" 
  --description "Standart kullanım planı" 
  --api-stages "apiId=${API_ID},stage=prod" 
  --throttle "burstLimit=100,rateLimit=50" 
  --quota "limit=10000,period=MONTH" 
  --query 'id' 
  --output text 
  --region ${REGION})

echo "Usage Plan ID: ${USAGE_PLAN_ID}"

# API key'i usage plan'a bağla
aws apigateway create-usage-plan-key 
  --usage-plan-id ${USAGE_PLAN_ID} 
  --key-id ${API_KEY_ID} 
  --key-type API_KEY 
  --region ${REGION}

# /products GET metodunu API key zorunlu hale getir
aws apigateway update-method 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method GET 
  --patch-operations op=replace,path=/apiKeyRequired,value=true 
  --region ${REGION}

Throttle parametreleri:

  • rateLimit: Saniyede izin verilen ortalama istek sayısı
  • burstLimit: Anlık izin verilen maksimum istek sayısı (token bucket algoritması)
  • limit: Belirlenen periyotta toplam istek kotası
  • period: Kota sıfırlama periyodu (DAY, WEEK, MONTH)

CloudWatch Logging Aktif Etme

Production ortamında loglar olmadan sorun gidermek neredeyse imkansız. API Gateway’de detaylı logging açalım.

# CloudWatch Logs için IAM rolü oluştur
aws iam create-role 
  --role-name api-gateway-cloudwatch-role 
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "Service": "apigateway.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }
    ]
  }'

aws iam attach-role-policy 
  --role-name api-gateway-cloudwatch-role 
  --policy-arn arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs

CLOUDWATCH_ROLE_ARN=$(aws iam get-role 
  --role-name api-gateway-cloudwatch-role 
  --query 'Role.Arn' 
  --output text)

# Account level'da CloudWatch rolünü ayarla
aws apigateway update-account 
  --patch-operations op=replace,path=/cloudwatchRoleArn,value=${CLOUDWATCH_ROLE_ARN} 
  --region ${REGION}

# Stage'de logging'i aktif et
aws apigateway update-stage 
  --rest-api-id ${API_ID} 
  --stage-name prod 
  --patch-operations 
    op=replace,path=/accessLogSettings/destinationArn,value="arn:aws:logs:${REGION}:${ACCOUNT_ID}:log-group:API-Gateway-Access-Logs_${API_ID}/prod" 
    op=replace,path=/*/*/logging/dataTrace,value=true 
    op=replace,path=/*/*/logging/loglevel,value=INFO 
    op=replace,path=/*/*/metrics/enabled,value=true 
  --region ${REGION}

CORS Yapılandırması

Web uygulamaları için CORS (Cross-Origin Resource Sharing) yapılandırması kaçınılmaz. Özellikle frontend’in farklı bir domain’de olduğu durumlarda.

# OPTIONS metodu ekle (CORS preflight için)
aws apigateway put-method 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method OPTIONS 
  --authorization-type NONE 
  --region ${REGION}

# OPTIONS için MOCK entegrasyonu
aws apigateway put-integration 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method OPTIONS 
  --type MOCK 
  --request-templates '{"application/json": "{"statusCode": 200}"}' 
  --region ${REGION}

# OPTIONS integration response
aws apigateway put-integration-response 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method OPTIONS 
  --status-code 200 
  --response-parameters '{
    "method.response.header.Access-Control-Allow-Headers": "'"'"'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"'"'",
    "method.response.header.Access-Control-Allow-Methods": "'"'"'GET,POST,OPTIONS'"'"'",
    "method.response.header.Access-Control-Allow-Origin": "'"'"'https://sizin-domain.com'"'"'"
  }' 
  --region ${REGION}

# OPTIONS method response
aws apigateway put-method-response 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method OPTIONS 
  --status-code 200 
  --response-parameters '{
    "method.response.header.Access-Control-Allow-Headers": false,
    "method.response.header.Access-Control-Allow-Methods": false,
    "method.response.header.Access-Control-Allow-Origin": false
  }' 
  --region ${REGION}

# Değişikliklerden sonra yeniden deploy et
aws apigateway create-deployment 
  --rest-api-id ${API_ID} 
  --stage-name prod 
  --description "CORS yapılandırması eklendi" 
  --region ${REGION}

CORS konusunda dikkat: Access-Control-Allow-Origin: * kullanmak test için işe yarar ama production’da asla. Sadece güvendiğiniz origin’leri ekleyin.

Custom Domain Name Yapılandırması

Production’da API URL’i doğrudan kullanmak yerine kendi domain’inizle çalışmak çok daha profesyonel ve yönetilebilir bir yapı sunar.

# Önce ACM'de sertifika olması gerekiyor (us-east-1 bölgesinde!)
# REGIONAL endpoint için sertifika aynı bölgede olmalı

# Mevcut sertifikaları listele
aws acm list-certificates 
  --certificate-statuses ISSUED 
  --region ${REGION} 
  --query 'CertificateSummaryList[*].[DomainName,CertificateArn]' 
  --output text

CERT_ARN="arn:aws:acm:eu-west-1:${ACCOUNT_ID}:certificate/your-cert-id"

# Custom domain oluştur
aws apigateway create-domain-name 
  --domain-name "api.sizin-domain.com" 
  --regional-certificate-arn ${CERT_ARN} 
  --endpoint-configuration types=REGIONAL 
  --region ${REGION}

# Base path mapping oluştur
aws apigateway create-base-path-mapping 
  --domain-name "api.sizin-domain.com" 
  --rest-api-id ${API_ID} 
  --stage prod 
  --base-path "v1" 
  --region ${REGION}

# Regional domain name'i öğren (Route53'e eklemek için)
aws apigateway get-domain-name 
  --domain-name "api.sizin-domain.com" 
  --query 'regionalDomainName' 
  --output text 
  --region ${REGION}

Bu komuttan dönen değeri Route53’de alias record olarak eklemeniz gerekiyor. Böylece api.sizin-domain.com/v1/products şeklinde erişebilirsiniz.

Hata Ayıklama ve Yaygın Sorunlar

Sahada en sık karşılaşılan sorunlar ve çözümleri:

403 Forbidden hatası: API key zorunlu yapılandırılmışsa ama request’te x-api-key header’ı yoksa bu hata alınır.

# Doğru kullanım
curl -X GET "https://${API_ID}.execute-api.${REGION}.amazonaws.com/prod/products" 
  -H "x-api-key: your-api-key-value"

502 Bad Gateway hatası: Lambda fonksiyonunuzun döndürdüğü response formatı yanlışsa bu hatayı alırsınız. Lambda’nın statusCode, headers ve body alanlarını içeren bir JSON döndürdüğünden emin olun.

CORS hatası: Preflight OPTIONS isteğine doğru header’lar dönmüyorsa veya actual response’da Access-Control-Allow-Origin header’ı yoksa browser bu hatayı verir. Lambda response’unuzda bu header’ı döndürmeniz gerektiğini unutmayın.

Timeout hatası: API Gateway’nin default timeout’u 29 saniye. Lambda’nız 30 saniye timeout’a ayarlıysa bu uyumsuzluk sorun çıkarır. Her zaman API Gateway timeout’unu Lambda timeout’undan küçük tutun.

# Stage'deki timeout ayarlarını kontrol et
aws apigateway get-stage 
  --rest-api-id ${API_ID} 
  --stage-name prod 
  --region ${REGION}

# Belirli bir metodun integration ayarlarını kontrol et
aws apigateway get-integration 
  --rest-api-id ${API_ID} 
  --resource-id ${PRODUCTS_RESOURCE_ID} 
  --http-method GET 
  --region ${REGION}

Maliyet Optimizasyonu Notları

API Gateway maliyeti kullanıma göre değişiyor ve dikkat edilmezse bütçeyi aşabilirsiniz.

REST API maliyet kalemleri:

  • API çağrıları: Milyonlar ile ölçülür, ilk 333 milyon çağrı aylık ~3.50 USD
  • Data transfer: GB başına ücretlendirme
  • Cache: Aktif ederseniz saatlik ücret
  • Private API: VPC endpoint maliyeti ayrıca işler

Caching aktif etmek hem maliyeti hem de Lambda invocation sayısını düşürür. Sık değişmeyen veriler için kesinlikle değerlendirin:

# Stage'de cache aktif et (dikkat: ekstra maliyet!)
aws apigateway update-stage 
  --rest-api-id ${API_ID} 
  --stage-name prod 
  --patch-operations 
    op=replace,path=/cacheClusterEnabled,value=true 
    op=replace,path=/cacheClusterSize,value=0.5 
    op=replace,path=/*/*/caching/enabled,value=true 
    op=replace,path=/*/*/caching/ttlInSeconds,value=300 
  --region ${REGION}

0.5 GB cache en küçük boyut ve aylık yaklaşık 14 USD maliyeti var. Küçük uygulamalar için gereksiz olabilir, buna göre karar verin.

Sonuç

AWS API Gateway ile REST API oluşturmak birkaç CLI komutu çalıştırmaktan çok daha fazlasını gerektiriyor. Doğru bir production kurulumu için; throttling ve usage plan, CloudWatch logging, CORS yapılandırması, custom domain ve sertifika yönetimi, Lambda izinleri ve IAM rolleri gibi konuların hepsini birlikte düşünmek gerekiyor.

Bu yazıda anlattığımız yapı, küçükten orta büyüklüğe kadar çoğu uygulama için sağlam bir başlangıç noktası sunuyor. İlerleyen aşamada Cognito ile kimlik doğrulama, WAF entegrasyonu ve Terraform/CDK ile infrastructure as code’a geçiş gibi konuları da ele almak gerekecek, bunları ayrı yazılarda detaylandıracağız.

En önemli tavsiye: her değişiklikten sonra yeniden deploy etmeyi unutmayın. API Gateway’de en sık yapılan hata, yapılandırmayı güncelleyip deploy etmemek ve “neden çalışmıyor?” diye saatlerce debug yapmak. Stage’e deploy etmeden hiçbir değişiklik prod ortamına yansımaz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir