API Tasarımı & Sürüm Yönetimi 3 dk okuma 3 okunma

API Tasarımında Backward Compatibility Sağlama

Backward compatibility, API evrilirken mevcut istemcilerin çalışmaya devam etmesini sağlar. Anahtar ilke additive change (ekleme yap, çıkarma yapma) ve tolerant reader (bilinmeyen alanları görmezden gel, eksik alanlara dayanıklı ol) yaklaşımıdır. Breaking değişiklikler için yeni sürüm, deprecation başlıkları (Sunset, Deprecation) ve kontrat testleri gerekir. Tüm değişiklikler OpenAPI diff ile CI/CD'de otomatik doğrulanmalıdır.

API Tasarımında Backward Compatibility Sağlama

API Tasarımında Backward Compatibility Sağlama

Bir API yayınlandığı anda, onu tüketen istemcilerle bir sözleşme (contract) imzalamış olursunuz. Bu sözleşmeyi bozan değişiklikler; mevcut istemcilerin çökmesine, veri kaybına ve itibar kaybına yol açar. Backward compatibility (geriye dönük uyumluluk), API'nizi geliştirmeye devam ederken eski istemcilerin çalışmaya devam etmesini sağlayan disiplindir.


1. Breaking vs. Non-Breaking Değişiklikler

Değişiklik Breaking mi? Açıklama
Yeni endpoint ekleme ❌ Mevcut istemciler kullanmak zorunda değil
Yeni opsiyonel alan (yanıt) ❌ Tolerant reader görmezden gelir
Yeni opsiyonel query parametresi ❌ Varsayılan değer kullanılır
Yeni zorunlu alan (istek) ✅ Eski istemciler bu alanı göndermez
Alan kaldırma (yanıt) ✅ İstemciler null/undefined alır
Alan tipi değiştirme ✅ int → string dönüşümü bozar
Alan adı değiştirme ✅ İstemciler eski adı arar
HTTP durum kodu değiştirme ✅ İstemci mantığını bozar
Varsayılan davranış değiştirme ✅ Sessiz davranış değişikliği

Altın Kural: Emin değilseniz, breaking olduğunu varsayın ve yeni sürüm planlayın.


2. Additive Change: Ekle, Çıkarma

Backward compatibility'nin temel prensibi: mevcut yapıya ekleme yapın, çıkarma yapmayın.

✅ Non-Breaking:

json

// V1
{ "id": 123, "name": "Laptop", "price": 1500 }

// V1 + Yeni Alan
{ "id": 123, "name": "Laptop", "price": 1500, "currency": "TRY" }

❌ Breaking:

json

// V1
{ "id": 123, "name": "Laptop", "price": 1500 }

// V1 + Alan Kaldırma
{ "id": 123, "name": "Laptop" }

3. Tolerant Reader Pattern

Backward compatibility sadece sunucunun değil, istemcinin de sorumluluğudur. Tolerant Reader, istemcinin tanımadığı alanları görmezden gelmesi ve eksik alanlara karşı dayanıklı olmasıdır.

❌ Kırılgan İstemci:

csharp

// Yanıtın tam olarak beklenen formatta geldiğini varsayar
var price = data.price; // "price" yoksa hata!

✅ Hoşgörülü İstemci:

csharp

public class ProductDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal? Price { get; set; }              // Nullable
    public string Currency { get; set; } = "TRY";    // Varsayılan
}

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};

Tolerant Reader Kuralları: Yeni alanları görmezden gel, eksik alanlara varsayılan değer kullan, alan sırasına bağımlı olma, hata mesajlarını parse etme.


4. Breaking Değişiklikler için Strateji: Expand/Contract

Yeniden adlandırma veya tip değişikliği gibi breaking değişiklikler, üç adımda güvenle yapılabilir:

Adım 1 (Expand): Yeni alanı ekle, eski alanı koru.

json

{ "price": 1500, "priceAmount": 1500, "currency": "TRY" }

Adım 2 (Migrate): Tüm istemciler yeni alana geçene kadar bekle.

Adım 3 (Contract): Eski alanı kaldır.

json

{ "priceAmount": 1500, "currency": "TRY" }

5. Sürümleme ve Deprecation Süreci

Adım 1: Yeni sürümü paralel yayınlayın.

text

/api/v1/products   ← Eski (çalışmaya devam ediyor)
/api/v2/products   ← Yeni

Adım 2: Eski sürümü "deprecated" işaretleyin.

csharp

[ApiVersion("1.0", Deprecated = true)]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ProductsController : ControllerBase { ... }

Adım 3: Deprecation başlıkları ekleyin.

csharp

context.Response.Headers.Append("Deprecation", "true");
context.Response.Headers.Append("Sunset", "Sat, 31 Dec 2026 23:59:59 GMT");
context.Response.Headers.Append("Link", "</api/v2/products>; rel=\"successor-version\"");

Sunset başlığı, eski sürümün ne zaman kapatılacağını bildirir. Link başlığı yeni sürüme işaret eder.

Adım 4: Geçiş süresi tanıyın (6-12 ay).

Adım 5: Eski sürümü kapatın (410 Gone).


6. Otomatik Doğrulama: OpenAPI Diff

Backward compatibility'yi CI/CD'de otomatik doğrulamak, insan hatasını ortadan kaldırır. oasdiff gibi araçlar, iki OpenAPI şemasını karşılaştırarak breaking değişiklikleri tespit eder:

bash

oasdiff breaking api-v1.json api-v2.json

Pipeline'da breaking değişiklik bulunursa, build başarısız olur ve deploy durur. Bu, "fark etmeden bozma" riskini sıfırlar.


7. En İyi Pratikler

Pratik Açıklama
Tolerant Reader olun İstemciler yeni alanları görmezden gelsin, eksik alanlara dayanıklı olsun.
Additive change yapın Mevcut yapıya ekleme yapın, çıkarma yapmayın.
Breaking değişiklikleri sürümleyin Yeni sürüm oluşturun; eskiyi koruyun.
Deprecation başlıkları kullanın Sunset ve Deprecation ile istemcileri otomatik bilgilendirin.
Kontrat testleri yazın API sözleşmesini otomatik testlerle koruyun.
OpenAPI diff'i CI/CD'ye ekleyin Breaking değişiklikleri merge öncesi yakalayın.
Geçiş süresi tanıyın İstemcilere yeni sürüme geçmeleri için makul süre verin.

Sonuç

Backward compatibility, bir API'nin uzun vadeli başarısının anahtarıdır. Breaking değişikliklerden kaçınmak, additive change prensibini benimsemek, tolerant reader pattern'ini uygulamak, sürümleme ve deprecation süreçlerini doğru yönetmek, mevcut istemcilerinizi korurken API'nizi geliştirmeye devam etmenizi sağlar. Unutmayın: Bir API yayınlandığında, onu tüketen istemcilerle bir sözleşme imzalamış olursunuz; bu sözleşmeyi bozan değişiklikler, güven kaybına ve itibar kaybına yol açar.

Tüm yazılar Soru ya da yorumun mu var? Yaz