API Versioning Stratejileri: İlk Release'den Sunset'a Kadar
URL ve header versioning yaklaşımları, breaking change yönetimi, Sunset header'ları ile deprecation, AWS API Gateway pattern'leri, GraphQL schema evolution ve consumer-driven contract testing'i kapsayan kapsamlı bir API versioning rehberi.
API versioning sadece URL'lerine /v2/ eklemekten ibaret değil. Farklı takımlarla API'ler üzerinde çalışmak bana versioning stratejisinin client migration timeline'larından infrastructure maliyetlerine kadar her şeyi etkilediğini öğretti. Production sistemleri bozmadan API evolution'ı yönetme konusunda öğrendiklerimi paylaşıyorum.
Özet
API versioning, backward compatibility ile forward progress arasında denge kurmayı gerektirir. Bu rehber, URL path ve header versioning karşılaştırması, OpenAPI diff tool'ları ile breaking change yönetimi, RFC 8594 deprecation header'larının implementasyonu, Lambda alias'ları ile AWS API Gateway versioning pattern'leri, traditional versioning olmadan GraphQL schema evolution, Pact ile consumer-driven contract testing ve koordineli migration pattern'lerini kapsar. Yaklaşım, continuous API improvement'ı sağlarken disruption'ı minimize etmek için gradual rollout'lar, comprehensive monitoring ve clear communication'a odaklanır.
Teknik Challenge
API evolution birkaç birbirine bağlı problem yaratır:
Breaking Change Management: Bir field'ı name'den fullName'e rename ettiğinde, name bekleyen mevcut client'lar fail olur. Soru breaking change'lerin yapılıp yapılmaması değil; production incident'larına neden olmadan nasıl yapılacağıdır.
Version Proliferation: Sunset policy olmadığı için altı concurrent API version'ı destekleyen takımlar gördüm. Her version testing matrix'ini, security patch burden'ını ve infrastructure maliyetlerini katlar. Engineering time hızla birikiyor.
Migration Coordination: API'nize 50 farklı client depend ettiğinde, zero-downtime migration'ları coordinate etmek complex hale geliyor. Bazı client'lar hemen update oluyor, diğerleri aylar alıyor. Her ikisini de accommodate eden bir stratejiye ihtiyacın var.
Documentation Synchronization: Birden fazla API version'ında OpenAPI spec'leri, SDK version'larını ve documentation'ı maintain etmek, birçok versioning stratejisinin başarısız olduğu nokta. Doc'lar gerçeklikten uzaklaşıyor, integration confusion'a neden oluyor.
Versioning Stratejini Seçmek
Üç ana yaklaşım var, her birinin spesifik trade-off'ları mevcut:
URL Path Versioning
Avantajlar: URL'lerde explicit versioning, browser'da test etmesi straightforward, excellent CDN cache efficiency (farklı URL'ler = ayrı cache key'ler).
Dezavantajlar: URL change'leri bookmark'ları ve hardcoded client'ları bozar, her version için routing configuration gerekir.
Ne zaman kullanılır: Clarity'nin URL aesthetic'ten daha önemli olduğu, multiple major version'lı public API'ler için. Twitter, Stripe ve GitHub (historically) bu yaklaşımı kullanır.
Header-Based Versioning
Avantajlar: Değişmeyen clean URL'ler, granular version control, content negotiation pattern'lerini destekler.
Dezavantajlar: API client'lar olmadan test etmesi daha zor, log'larda header'ları specifically log etmediğin sürece version invisible, cache configuration Vary header setup gerektirir.
Ne zaman kullanılır: Internal API'ler, frequent minor update'li API'ler, URL stability'nin önemli olduğu sistemler için. GitHub (current approach) ve Microsoft Graph API bu pattern'i kullanır.
Decision Framework
Seçim specific context'ine bağlı. External partner'lı public REST API için URL path versioning clarity sağlar. Internal microservice'ler için header versioning flexibility sunar. Tight consumer-provider coupling'li takımlar için GraphQL evolution modeli versioning complexity'sini elimine eder.
Breaking vs Non-Breaking Change'ler
Breaking change'in ne olduğunu anlamak accidental production incident'ları önler:
Non-Breaking (Güvenli) Change'ler:
- Yeni endpoint'ler eklemek
- Optional request parameter'lar eklemek
- Response'lara yeni field'lar eklemek (existing client'lar ignore eder)
- Mevcut code'ları valid tutarken yeni response status code'ları eklemek
- Validation rule'larını relax etmek (daha fazla input format kabul etmek)
Breaking Change'ler (Yeni Version Gerektirir):
- Endpoint'leri remove veya rename etmek
- Request/response field'larını remove veya rename etmek
- Field data type'larını değiştirmek (string'den number'a)
- Required request parameter eklemek
- Authentication mechanism'larını değiştirmek
- Error response structure'larını modify etmek
- HTTP method'ları değiştirmek (GET'ten POST'a)
Practice'te breaking olmadan evolution şöyle görünür:
Automated detection hataları önler. CI/CD pipeline'larda:
Deprecation'ı Doğru Implement Etmek
Deprecation bir event değil; bir process'tir. Realistic timeline:
Timeline'ı programmatically communicate etmek için RFC 8594 deprecation header'larını implement et:
Client SDK'lar deprecation'ı detect edip warn etmeli:
Hard shutdown yerine gradual throttling migration panic'ini azaltır:
AWS API Gateway Versioning Pattern'leri
AWS API Gateway birkaç versioning yaklaşımı sunar. Production'da çalışanlar:
Custom Domain ile Base Path Mapping
Bu, version'lar arasında complete isolation ile https://api.example.com/v1/users/123 ve https://api.example.com/v2/users/123 gibi clean URL'ler oluşturur.
CloudFront ile Header-Based Routing
Header versioning için Lambda@Edge request'leri route eder:
Bu yaklaşım header-based version selection'ı desteklerken URL'leri clean tutar.
GraphQL Schema Evolution
GraphQL'in felsefesi REST versioning'den farklı. Tüm API'yi version'lamak yerine, field deprecation kullanarak schema'yı continuously evolve ediyorsun:
name ve phone query eden client'lar çalışmaya devam eder. Yeni client'lar firstName, lastName ve contactInfo query eder. GraphQL introspection API deprecation warning'lerini gösterir.
Field-level version tracking için custom directive'ler yardımcı olur:
Resolver'lar deprecated field kullanımını track edebilir:
Consumer-Driven Contract Testing
Contract testing consumer'lar ve provider'lar arasında version compatibility'yi ensure eder. Pact en established tool:
Backend team tüm consumer contract'ları verify eder:
Bu, breaking change'leri production'a ulaşmadan yakalar. Frontend fullName beklediğinde ama backend name döndürdüğünde, contract test provider verification'da fail olur.
Migration Pattern'leri
Traffic Splitting ile Parallel Run
Gradual rollout risk'i azaltır:
Feature flag'lerle implement et:
LaunchDarkly dashboard'u ile percentage'ı gradually artır: 10% → 25% → 50% → 75% → 100% birkaç hafta boyunca.
Shadow Mode Testing
Response'ları etkilemeden yeni version'ı test et:
Bu, risk olmadan production load altında V2 behavior'ını validate eder.
Backward Compatibility için Adapter Pattern
Her iki version'ı destekleyen unified endpoint:
Version Kullanımını Monitor Etmek
Hangi client'ların hangi version'ları kullandığını track et:
Migration progress report'ları generate et:
Yaygın Hatalar
Yetersiz Deprecation Notice: Shutdown'dan sadece 3 ay önce sunset duyurmak client'ları zor duruma sokar. Public API'ler için minimum 12 ay daha iyi çalışır.
Minor Version'larda Breaking Change: Required field ekleyip 2.0.0 yerine 1.3.0 demek semantic versioning beklentilerini bozar. Bunu yakalamak için CI/CD'de automated OpenAPI diff kullan.
Version Proliferation: 6+ concurrent version desteklemek engineering maliyetlerini katlar. Strict sunset policy yardımcı olur: maksimum 3 version (current + previous + deprecated).
Inconsistent SDK Versioning: API version 1 ile çalışan SDK version 2.3.0 developer'ları şaşırtır. SDK major version'ını API major version'ıyla align et.
Missing Contract Test'ler: Backend değişiklikleri frontend'i bozar çünkü V1 adapter compatibility test edilmemiştir. Pact bunu önler.
Unversioned Error Response'lar: Sadece success response'ları version'larken error format'ı değişirse client error handling bozulur. Error'ları consistently version'la.
Deprecation Monitoring Yok: Major client'ların hala kullandığı V1'i bilmeden kapatmak revenue-impacting outage'lara neden olur. Sunset'tan önce usage'ı track et.
Önemli Çıkarımlar
-
Audience'a göre versioning seç: Public API'ler için URL path, internal için header'lar, rapid iteration için GraphQL evolution.
-
Breaking change detection'ı automate et: CI/CD'deki OpenAPI diff tool'ları accidental breaking change'leri önler.
-
Deprecation 12+ ay gerektirir: Multi-channel communication (header'lar, email, doc'lar), usage monitoring, hard shutdown yerine gradual throttling.
-
Concurrent version'ları sınırla: Maksimum 3 active version technical debt explosion'ını önler.
-
Gradual rollout kullan: Feature flag'lerle 10% → 25% → 50% → 100% traffic splitting migration risk'ini azaltır.
-
Contract testing break'leri önler: Pact, consumer'lar ve provider'lar arasındaki incompatibility'leri production'dan önce yakalar.
-
GraphQL versioning complexity'sini elimine eder: Field-level deprecation version explosion olmadan smooth migration sağlar.
-
Version usage'ı continuously monitor et: Deprecated version'ları kullanan client'ları track et, straggler'ları erken identify et.
Çalışan versioning stratejisi specific context'ine bağlı; public vs internal API, consumer sayısı, change frequency. Requirement'larını karşılayan en basit yaklaşımla başla, sadece gerektiğinde complexity ekle.