API Deprecation Yönetimi: Geriye Dönük Uyumluluk Stratejileri
Üretim ortamında çalışan bir API’yi deprecate etmek, geceleri uyutmayan türden bir operasyon. Yanlış yapılırsa müşteri şikayetleri, bozuk entegrasyonlar ve acil sabah toplantıları sizi bekliyor. Doğru yapılırsa ise kimse farkına bile varmaz, ki bu aslında en iyi senaryo. Bu yazıda API deprecation yönetimini, geriye dönük uyumluluğu nasıl koruyacağınızı ve production ortamında bu süreci nasıl sorunsuz yürüteceğinizi konuşacağız.
API Deprecation Nedir ve Neden Bu Kadar Kritik
API deprecation, bir API versiyonunun veya endpoint’inin artık desteklenmeyeceğini duyurma ve kullanıcıları yeni versiyona geçirme sürecidir. Kulağa basit geliyor, ama gerçekte yüzlerce client’ın, onlarca şirketin ve bazen binlerce son kullanıcının etkilendiği hassas bir operasyon.
Yanlış yapılan bir deprecation’ın bedeli ağır olabilir:
- Broken integrations: Partner firmaların entegrasyonları aniden çalışmayı duyabilir
- Revenue loss: E-ticaret entegrasyonlarında kesinti direkt gelir kaybına dönüşür
- Güven kaybı: Geliştiriciler API’nize güvenmezse bir daha geri dönmezler
- Support yükü: Her gelen “neden çalışmıyor” sorusu ekibinizin zamanını çalar
Geriye dönük uyumluluk ise şu anlama gelir: Eski client’lar, yeni API versiyonuyla herhangi bir değişiklik yapmadan çalışmaya devam edebilmelidir. Bu her zaman mümkün olmasa da mümkün olduğunca uzun süre sağlanması gerekir.
Versiyonlama Stratejileri
Deprecation sürecinin temeli iyi bir versiyonlama stratejisidir. Üç ana yaklaşım var:
URL Tabanlı Versiyonlama
En yaygın ve en anlaşılır yöntem. Client’lar hangi versiyonu kullandıklarını tam olarak bilirler.
# v1 endpoint
curl -X GET https://api.sirketim.com/v1/users/123
# v2 endpoint
curl -X GET https://api.sirketim.com/v2/users/123
Header Tabanlı Versiyonlama
# Accept header ile versiyon belirleme
curl -X GET https://api.sirketim.com/users/123
-H "Accept: application/vnd.sirketim.v2+json"
-H "Authorization: Bearer TOKEN_BURAYA"
# API-Version header ile
curl -X GET https://api.sirketim.com/users/123
-H "API-Version: 2024-01-15"
-H "Authorization: Bearer TOKEN_BURAYA"
Header tabanlı versiyonlama temiz URL’ler sağlar ama client’lar için daha karmaşıktır. Stripe’ın kullandığı tarih tabanlı versiyonlama (örneğin 2024-01-15) oldukça iyi çalışır çünkü tam olarak hangi değişikliğin ne zaman yapıldığını gösterir.
Query Parameter Versiyonlama
# Query param ile
curl -X GET "https://api.sirketim.com/users/123?version=2"
Bu yöntem en az önerilen. Önbellek sorunları yaratır ve test etmesi zordur.
Deprecation Header’larını Doğru Kullanmak
IETF’nin draft-ietf-httpapi-deprecation-header standardı, deprecation bilgisini HTTP header’ları üzerinden iletmek için bir format tanımlar. Nginx veya API gateway seviyesinde bunu şöyle uygulayabilirsiniz:
# Nginx konfigürasyonu - deprecated endpoint için header ekle
location /v1/ {
# Deprecation tarihini RFC 7231 formatında belirt
add_header "Deprecation" "Sun, 01 Jan 2025 00:00:00 GMT" always;
add_header "Sunset" "Mon, 01 Jul 2025 00:00:00 GMT" always;
add_header "Link" '<https://api.sirketim.com/v2/>; rel="successor-version"' always;
proxy_pass http://backend_v1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /v2/ {
proxy_pass http://backend_v2;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
Deprecation: Endpoint’in ne zaman deprecated edildiği Sunset: Endpoint’in tamamen kapatılacağı tarih Link: Yeni versiyonun URL’si
Bu header’ları gören iyi yazılmış client’lar otomatik uyarı verebilir. Kötü yazılmış client’lar görmez, ama en azından siz görevinizi yapmış olursunuz.
Gerçek Dünya Senaryosu: Kullanıcı API’si Migrasyonu
Diyelim ki /v1/users endpoint’inizde kullanıcı adı ve soyadı ayrı field’larda dönüyor (first_name, last_name), ama yeni versiyonda bunu tek full_name field’ına geçirmek istiyorsunuz. Aynı zamanda telefon numarası formatını da değiştiriyorsunuz.
Bu tür breaking change’leri yönetmek için bir geçiş katmanı yazabilirsiniz:
# Python Flask örneği - Geriye dönük uyumluluk katmanı
# v1_compatibility.py dosyası için test
# Önce yeni API'nin cevabını test edelim
curl -X GET https://api.sirketim.com/v2/users/123
-H "Authorization: Bearer $API_TOKEN" | python3 -m json.tool
# Beklenen v2 cevabı:
# {
# "id": 123,
# "full_name": "Ahmet Yilmaz",
# "phone": "+90-212-555-0101"
# }
# v1 client'ının aldığı cevap (compatibility layer sonrası):
# {
# "id": 123,
# "first_name": "Ahmet",
# "last_name": "Yilmaz",
# "phone": "02125550101"
# }
Compatibility layer’ı ayrı bir servis olarak konuşlandırmak en temiz çözümdür. Bu sayede eski kodu korumak zorunda kalmazsınız, sadece bir transform katmanı yazarsınız.
Deprecation Loglarını İzlemek
Hangi client’ların hala eski versiyonu kullandığını bilmeden deprecation sürecini yönetemezsiniz. Nginx access log’larını şu şekilde yapılandırın:
# /etc/nginx/nginx.conf - özel log format
http {
log_format api_deprecation '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'api_version="$api_version" '
'client_id="$http_x_client_id"';
# v1 trafiğini ayrı log dosyasına yaz
server {
listen 443 ssl;
server_name api.sirketim.com;
location /v1/ {
access_log /var/log/nginx/api_v1_deprecated.log api_deprecation;
add_header "Deprecation" "true" always;
proxy_pass http://backend_v1;
}
}
}
Log’ları parse edip kim hala v1 kullanıyor diye bakmak için:
# Son 24 saatte v1 endpoint'ini kullanan unique client'lar
grep "$(date +%d/%b/%Y)" /var/log/nginx/api_v1_deprecated.log |
grep -oP 'client_id="K[^"]+' |
sort | uniq -c | sort -rn | head -20
# Saatlik v1 request sayısını izle
awk '{print $4}' /var/log/nginx/api_v1_deprecated.log |
cut -d: -f1-3 |
sort | uniq -c
# v1 kullanan User-Agent'ları listele (hangi uygulamalar bağlanıyor)
grep -oP '"[A-Z]+ /v1[^"]*" d+ d+ "[^"]*" "K[^"]+'
/var/log/nginx/api_v1_deprecated.log |
sort | uniq -c | sort -rn
Bu komutları cron job’a koyun ve her sabah bir rapor alın. Hangi müşterinin hala eski versiyonu kullandığını görünce onları proaktif olarak uyarabilirsiniz.
Sunset Politikası Belirlemek
Sunset tarihi belirlerken şu faktörleri göz önünde bulundurun:
- Müşteri sayısı ve büyüklüğü: 500 küçük müşteri ile 5 büyük enterprise müşteri farklı zaman dilimlerine ihtiyaç duyar
- Integration karmaşıklığı: Basit bir REST call ile karmaşık bir veri pipeline’ı çok farklı migration süreleri gerektirir
- Seasonal traffic: Perakende sektöründe yılbaşı öncesi kimse migration yapmaz
- Minimum süre: B2B API’ler için 6 ay, public API’ler için 12 ay makul başlangıç noktaları
Sunset politikanızı dokumentasyona yazmanın yanı sıra her API response’una da ekleyin:
# API response'larına deprecation bilgisi ekleme
# Middleware örneği - Express.js benzeri bir yapı için curl testi
# Deprecated endpoint'i çağır ve header'ları incele
curl -v https://api.sirketim.com/v1/products
-H "Authorization: Bearer $TOKEN" 2>&1 | grep -E "(< |Deprecation|Sunset|Link)"
# Görmek istediğiniz çıktı:
# < HTTP/2 200
# < Deprecation: Sun, 01 Jan 2025 00:00:00 GMT
# < Sunset: Mon, 01 Jul 2025 00:00:00 GMT
# < Link: <https://api.sirketim.com/v2/products>; rel="successor-version"
# < X-Deprecation-Info: Bu endpoint 1 Temmuz 2025'te kapatilacaktir
Migration Guide ve İletişim Stratejisi
Teknik kısım çözdükten sonra iletişim gelir. Deprecation’ı duyurmanın birden fazla kanalda olması gerekir:
Email Notifikasyon Sistemi
API key’lerine bağlı email adreslerini tutuyorsanız (tutmuyorsanız tutmaya başlayın), deprecation öncesi e-posta gönderebilirsiniz. Hangi client’ların eski versiyonu kullandığını log’lardan tespit ettikten sonra:
# Aktif v1 kullanıcılarını database'den çekip mail listesi oluşturma
# Bu örnek PostgreSQL kullanıyor
psql -h localhost -U apiuser -d apidb -c "
SELECT DISTINCT
c.email,
c.company_name,
c.api_key,
COUNT(al.id) as request_count_last_30_days
FROM api_clients c
JOIN api_logs al ON c.api_key = al.client_api_key
WHERE al.endpoint LIKE '/v1/%'
AND al.created_at > NOW() - INTERVAL '30 days'
GROUP BY c.email, c.company_name, c.api_key
ORDER BY request_count_last_30_days DESC;
" > /tmp/v1_active_users.csv
# Kaç benzersiz müşteri etkilenecek
wc -l /tmp/v1_active_users.csv
Bu listeyi alın, müşteri başarı ekibinize verin veya doğrudan bir e-posta kampanyası başlatın. Yüksek request count’u olan müşterileri önceliklendirin, onlar migration konusunda daha fazla desteğe ihtiyaç duyabilir.
Canary Release ile Aşamalı Geçiş
Yeni versiyona geçişi bir anda yapmak yerine aşamalı yapın. Nginx upstream ağırlıklandırmasıyla başlayabilirsiniz:
# /etc/nginx/conf.d/api_upstream.conf
# Önce trafiğin %5'ini v2'ye yönlendir
upstream api_backend {
# v2 - yeni versiyon, düşük ağırlıkla başla
server backend-v2:8080 weight=5;
# v1 - eski versiyon, yüksek ağırlık
server backend-v1:8080 weight=95;
keepalive 32;
}
# Bir hafta sonra
upstream api_backend {
server backend-v2:8080 weight=50;
server backend-v1:8080 weight=50;
keepalive 32;
}
# Migration tamamlandığında
upstream api_backend {
server backend-v2:8080 weight=100;
# v1 burada hala duruyor ama trafik almıyor
server backend-v1:8080 weight=0 backup;
keepalive 32;
}
Bu aşamalı yaklaşım size v2’de beklenmedik bir sorun çıkınca hızlı geri dönme imkanı sağlar. Ağırlıkları değiştirmek için nginx -s reload yeterli, hiçbir downtime yok.
Breaking Change Tespiti ve Otomatik Test
Her yeni API değişikliği geriye dönük uyumluluğu bozup bozmadığını otomatik test edebilir. CI/CD pipeline’ınıza contract test’leri ekleyin:
#!/bin/bash
# api_compatibility_check.sh
# v1 ile v2 response'larını karşılaştır
V1_URL="https://api.sirketim.com/v1"
V2_URL="https://api.sirketim.com/v2"
TOKEN="$API_TEST_TOKEN"
FAILED=0
echo "=== API Geriye Donuk Uyumluluk Kontrolu ==="
# Her test endpoint'i icin
for endpoint in "users/1" "products/100" "orders/recent"; do
echo -n "Kontrol ediliyor: /$endpoint ... "
V1_RESPONSE=$(curl -s -o /tmp/v1_resp.json -w "%{http_code}"
"$V1_URL/$endpoint" -H "Authorization: Bearer $TOKEN")
V2_RESPONSE=$(curl -s -o /tmp/v2_resp.json -w "%{http_code}"
"$V2_URL/$endpoint" -H "Authorization: Bearer $TOKEN")
# HTTP status kodlarini karsilastir
if [ "$V1_RESPONSE" != "$V2_RESPONSE" ]; then
echo "HATA - Status farklı: v1=$V1_RESPONSE v2=$V2_RESPONSE"
FAILED=$((FAILED + 1))
continue
fi
# v1'de olan tum field'larin v2'de de oldugunu kontrol et
V1_KEYS=$(cat /tmp/v1_resp.json | python3 -c "
import json,sys
data = json.load(sys.stdin)
if isinstance(data, list): data = data[0] if data else {}
print('n'.join(sorted(data.keys())))
" 2>/dev/null)
V2_KEYS=$(cat /tmp/v2_resp.json | python3 -c "
import json,sys
data = json.load(sys.stdin)
if isinstance(data, list): data = data[0] if data else {}
print('n'.join(sorted(data.keys())))
" 2>/dev/null)
MISSING=$(comm -23 <(echo "$V1_KEYS") <(echo "$V2_KEYS"))
if [ -n "$MISSING" ]; then
echo "UYARI - v2'de eksik field'lar: $MISSING"
FAILED=$((FAILED + 1))
else
echo "OK"
fi
done
echo ""
if [ $FAILED -gt 0 ]; then
echo "SONUC: $FAILED kontrol basarisiz - breaking change olabilir!"
exit 1
else
echo "SONUC: Tum kontroller basarili"
exit 0
fi
Bu script’i CI/CD pipeline’ınızda her deployment öncesi çalıştırın. Breaking change varsa deployment durur, ekip bilgilendirilir.
Rate Limiting ile Eski Versiyon Kullanımını Caydırmak
Ekonomik teşvik çalışır. Eski versiyona daha sıkı rate limit uygulayarak migration’ı hızlandırabilirsiniz:
# /etc/nginx/conf.d/rate_limiting.conf
# v1 için sıkı rate limit
limit_req_zone $http_x_api_key zone=v1_deprecated:10m rate=100r/m;
# v2 için daha yüksek limit
limit_req_zone $http_x_api_key zone=v2_current:10m rate=1000r/m;
server {
location /v1/ {
limit_req zone=v1_deprecated burst=20 nodelay;
limit_req_status 429;
# 429 durumunda migration bilgisi ver
add_header "Retry-After" "60" always;
add_header "X-Migration-Guide" "https://docs.sirketim.com/api/v2-migration" always;
proxy_pass http://backend_v1;
}
location /v2/ {
limit_req zone=v2_current burst=200 nodelay;
proxy_pass http://backend_v2;
}
}
Rate limit mesajında migration guide URL’sini vermek önemli. Geliştirici 429 aldığında doğrudan dokümana yönlendirin, support’a ticket açmasına gerek kalmasın.
Acil Durum Planı: Eski Versiyon Geri Getirme
Her ne kadar planlayıp hazırlasanız da bazen eski versiyona geri dönmek zorunda kalabilirsiniz. Bu senaryoyu önceden hazırlayın:
#!/bin/bash
# api_rollback.sh - Acil durum geri alma script'i
set -e
ROLLBACK_VERSION="${1:-v1}"
CURRENT_VERSION="${2:-v2}"
echo "[$(date)] ROLLBACK BASLADI: $CURRENT_VERSION -> $ROLLBACK_VERSION"
# Nginx upstream'i geri al
sed -i "s/server backend-${ROLLBACK_VERSION}:8080 weight=0/server backend-${ROLLBACK_VERSION}:8080 weight=100/"
/etc/nginx/conf.d/api_upstream.conf
sed -i "s/server backend-${CURRENT_VERSION}:8080 weight=100/server backend-${CURRENT_VERSION}:8080 weight=0/"
/etc/nginx/conf.d/api_upstream.conf
# Nginx konfigurasyonunu test et
nginx -t
if [ $? -eq 0 ]; then
nginx -s reload
echo "[$(date)] Nginx reload basarili - trafik $ROLLBACK_VERSION'a yonlendirildi"
# Monitoring sistemine bildir
curl -s -X POST "$ALERTING_WEBHOOK"
-H "Content-Type: application/json"
-d "{"text": "API ROLLBACK: $CURRENT_VERSION -> $ROLLBACK_VERSION. Sebep: Manuel tetikleme"}"
else
echo "[$(date)] HATA: Nginx konfigurasyon hatasi, rollback basarisiz"
exit 1
fi
Bu script’i her ekip üyesinin kolayca çalıştırabileceği bir yere koyun. Gece 2’de panikle ne yapacağını bilen biri olmak istersiniz.
Monitoring ve Alert Yapılandırması
Deprecation döneminde normalden daha dikkatli izleme yapmanız gerekir. Prometheus ve Grafana kullanıyorsanız:
# prometheus.yml - API versiyon metrikleri topla
# Önce hangi metriklerin geldiğini kontrol et
curl -s http://localhost:9090/api/v1/query
--data-urlencode 'query=nginx_http_requests_total{request=~".*/v1/.*"}' |
python3 -m json.tool
# v1 error rate'ini alert rule olarak ekle
# /etc/prometheus/rules/api_deprecation.yml dosyasına:
cat << 'EOF'
groups:
- name: api_deprecation
rules:
- alert: DeprecatedAPIHighUsage
expr: rate(nginx_http_requests_total{request=~".*/v1/.*"}[5m]) > 100
for: 10m
labels:
severity: warning
annotations:
summary: "Deprecated v1 API hala yogun kullaniliyor"
description: "Son 5 dakikada {{ $value }} req/s v1 trafiği var"
- alert: DeprecatedAPIErrorSpike
expr: rate(nginx_http_requests_total{request=~".*/v1/.*",status=~"5.."}[5m]) > 10
for: 5m
labels:
severity: critical
annotations:
summary: "v1 API'de hata artisi"
description: "v1 endpoints 5xx hata orani artıyor: {{ $value }} req/s"
EOF
Sonuç
API deprecation yönetimi bir maraton, sprint değil. İyi bir süreç şu adımları takip eder: önce versiyonlama stratejisini belirle, deprecation header’larını ve log’larını doğru kur, kim kullanıyor tespit et, onlara proaktif ulaş, migration süresini gerçekçi belirle, aşamalı geçiş yap, otomatik uyumluluk testleri koy ve rollback planını hazır tut.
En sık yapılan hata, teknik hazırlığa odaklanıp iletişimi ihmal etmek. Mükemmel bir compatibility layer yazsanız bile müşterilerinize durumu açıklamazsanız, güven zedelenir. Diğer yaygın hata ise çok kısa sunset tarihi belirlemek. Müşterilerinizin de sprint planları, developer kaynakları ve öncelikleri var. Onlara nefes alacak zaman tanıyın.
Geriye dönük uyumluluk bir lüks değil, profesyonel API yönetiminin temel bileşenidir. Bunu iyi yapan şirketlerin API’leri uzun ömürlü olur, geliştirici ekosistemi büyür ve müşteri güveni sağlamlaşır. Kötü yapılanlar ise “API unreliable, başka bir şey bulalım” olarak anılır. Hangisi olmak istediğinizi siz bilirsiniz.
