.NET'te API Versioning: Stratejiler ve Uygulama

10 dakika okuma9 Mart 2026
API versioning .NETAsp.Versioning.NET API version strategyAPI deprecationREST API versioningMinimal API versioningAPI backward compatibilitySwagger versioning

# .NET'te API Versiyonlama Stratejileri

API'ler zamanla degisir. Alanlar yeniden adlandirilir, endpoint'ler yeniden yapilandirilir, yanit yapilari degisir. Birden fazla istemcinin kullandigi API'lerde -- mobil uygulamalar, partner entegrasyonlari, dahili frontend'ler -- versiyonlama ileriye gitmenizi saglayan ama geride kalanlari kirmayan bir sozlesmedir.

API Versiyonlama Neden Onemlidir

Bir API yayinladiginizda tuketiciler yanit yapilariniza, durum kodlariniza ve alan adlariniza gore kod yazar. Bunlardan birini degistirdiginiz an sozu bozarsiniz. Versiyonlama olmadan ekipler ya API'yi dondurur ya da sessiz kirilmalara yol acar. Her iki sonuc da güveni asindirır.

Versiyonlama Yaklasimlari Karsilastirmasi

URL Yolu ile Versiyonlama

GET /api/v1/products
GET /api/v2/products

En görünür ve yaygin yaklasimdir. Kesfetmesi, yonlendirmesi ve önbellek yönetimi kolaydir. API gateway'ler yol segmentlerine gore yonlendirme yapabilir. Dezavantaji URL kirliligidir.

Sorgu Dizgisi ile Versiyonlama

GET /api/products?api-version=1.0
GET /api/products?api-version=2.0

URL'leri daha temiz tutar ve uygulamasi kolaydir ama dokümantasyonda gözden kaçabilir. Önbellek proxy'leri sorgu parametrelerini yok sayabilir.

Header ile Versiyonlama

GET /api/products
X-Api-Version: 1.0

URL'yi tamamen temiz tutar ve versiyonlamayi kaynak tanimlamasindan ayirir. Dahili API'ler icin iyi calisir. Dezavantaji azalan kesfedilebilirliktir.

Medya Tipi ile Versiyonlama

GET /api/products
Accept: application/vnd.myapp.v2+json

Teoride en RESTful yaklasim olsa da, zayif araç destegi ve ek bilissel yük nedeniyle pratikte nadiren tercih edilir.

Asp.Versioning Kurulumu

`Asp.Versioning` kütüphanesi (eski adiyla `Microsoft.AspNetCore.Mvc.Versioning`) .NET'te API versiyonlama icin standarttir. Ilgili paketleri yükleyin:

csharp
class=class="code-string">"code-comment">// Controllerclass="code-string">'lar icin
dotnet add package Asp.Versioning.Mvc
dotnet add package Asp.Versioning.Mvc.ApiExplorer

class=class="code-string">"code-comment">// Minimal API'ler icin
dotnet add package Asp.Versioning.Http

Temel Yapilandirma

csharp
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(class="code-number">1, class="code-number">0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
    options.ApiVersionReader = ApiVersionReader.Combine(
        new UrlSegmentApiVersionReader(),
        new HeaderApiVersionReader(class="code-string">"X-Api-Version"),
        new QueryStringApiVersionReader(class="code-string">"api-version")
    );
})
.AddApiExplorer(options =>
{
    options.GroupNameFormat = class="code-string">"class="code-string">'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

`ReportApiVersions = true` her yanita `api-supported-versions` ve `api-deprecated-versions` basliklarini ekler.

Controller'lar ile Versiyonlama

csharp
[ApiController]
[Route(class="code-string">"api/v{version:apiVersion}/[controller]")]
[ApiVersion(class="code-string">"class="code-number">1.0")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        return Ok(new[]
        {
            new { Id = class="code-number">1, Name = class="code-string">"Widget", Price = class="code-number">9.99m }
        });
    }
}

[ApiController]
[Route(class="code-string">"api/v{version:apiVersion}/[controller]")]
[ApiVersion(class="code-string">"class="code-number">2.0")]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        return Ok(new[]
        {
            new { Id = class="code-number">1, Name = class="code-string">"Widget", UnitPrice = class="code-number">9.99m, Currency = class="code-string">"USD" }
        });
    }
}

Birden fazla versiyon ayni controller'i paylasabilir:

csharp
[ApiController]
[Route(class="code-string">"api/v{version:apiVersion}/[controller]")]
[ApiVersion(class="code-string">"class="code-number">1.0")]
[ApiVersion(class="code-string">"class="code-number">2.0")]
public class CustomersController : ControllerBase
{
    [HttpGet]
    [MapToApiVersion(class="code-string">"class="code-number">1.0")]
    public IActionResult GetV1() => Ok(new { Name = class="code-string">"Acme" });

    [HttpGet]
    [MapToApiVersion(class="code-string">"class="code-number">2.0")]
    public IActionResult GetV2() => Ok(new { Name = class="code-string">"Acme", Tier = class="code-string">"Enterprise" });
}

Minimal API'ler ile Versiyonlama

csharp
var versionSet = app.NewApiVersionSet()
    .HasApiVersion(new ApiVersion(class="code-number">1, class="code-number">0))
    .HasApiVersion(new ApiVersion(class="code-number">2, class="code-number">0))
    .ReportApiVersions()
    .Build();

var v1 = app.MapGroup(class="code-string">"api/v{version:apiVersion}/products")
    .WithApiVersionSet(versionSet)
    .MapToApiVersion(new ApiVersion(class="code-number">1, class="code-number">0));

var v2 = app.MapGroup(class="code-string">"api/v{version:apiVersion}/products")
    .WithApiVersionSet(versionSet)
    .MapToApiVersion(new ApiVersion(class="code-number">2, class="code-number">0));

v1.MapGet(class="code-string">"/", () => Results.Ok(new[]
{
    new { Id = class="code-number">1, Name = class="code-string">"Widget", Price = class="code-number">9.99m }
}));

v2.MapGet(class="code-string">"/", () => Results.Ok(new[]
{
    new { Id = class="code-number">1, Name = class="code-string">"Widget", UnitPrice = class="code-number">9.99m, Currency = class="code-string">"USD" }
}));

Versiyon sayisi arttikça rota kayitlarini ayri extension method'lara çikarmayi düsünün.

Versiyon Müzakeresi ve Varsayilan Versiyonlar

`AssumeDefaultVersionWhenUnspecified = true` ayari, versiyonsuz isteklerin varsayilan versiyonunuza düsmesini saglar. Geriye dönük uyumluluk icin kullanislidir ama sorunlari maskeleyebilir. Üretim ortaminda daha güvenli yaklasim:

csharp
options.AssumeDefaultVersionWhenUnspecified = false;

Desteklenmeyen versiyonlarda `400 Bad Request` döndürür ve tüketicileri bilinçli olmaya zorlar.

Kirici ve Kirici Olmayan Degisiklikler

Kirici Olmayan (versiyonlama olmadan güvenle eklenebilir)

  • Yanita yeni opsiyonel alanlar ekleme
  • Yeni bir endpoint ekleme
  • Opsiyonel sorgu parametreleri ekleme
  • Bir dogrulama kisitlamasini gevsetme
  • Kirici (yeni versiyon gerektirir)

  • Bir alani kaldirma veya yeniden adlandirma
  • Bir alanin veri tipini degistirme
  • Yanit yapisini degistirme (örn. yeni bir zarf ile sarma)
  • Hata yanit formatini degistirme
  • Daha önce opsiyonel olan bir alani zorunlu yapma
  • HTTP metodu veya durum kodu anlamini degistirme
  • Birden fazla istemcinin kullandigi API'lerde gri alanlar bariz kirmalardan daha fazla hasar verir. `string`'den `string | null`'a degismek teknik olarak eklemseldir ama null yönetimi yapmayan tüketiciyi çökertir. Emin degilseniz, versiyonlayin.

    Kullanim Disi Birakma Stratejisi ve Sunset Basliklari

    Eski versiyonlari emekliye ayirmak icin de bir plana ihtiyaciniz vardir. Versiyonlari kullanim disi olarak isaretleyin:

    csharp
    [ApiVersion(class="code-string">"class="code-number">1.0", Deprecated = true)]
    [ApiVersion(class="code-string">"class="code-number">2.0")]
    public class ProductsController : ControllerBase { }

    Veya Minimal API'lerde:

    csharp
    var versionSet = app.NewApiVersionSet()
        .HasDeprecatedApiVersion(new ApiVersion(class="code-number">1, class="code-number">0))
        .HasApiVersion(new ApiVersion(class="code-number">2, class="code-number">0))
        .Build();

    Kullanim disi versiyonlar çalismaya devam eder ama `api-deprecated-versions: 1.0` basligini içerir. Bunu RFC 8594 `Sunset` basligiyla tamamlayin:

    csharp
    app.Use(async (context, next) =>
    {
        await next();
    
        var apiVersion = context.GetRequestedApiVersion();
        if (apiVersion?.MajorVersion == class="code-number">1)
        {
            context.Response.Headers[class="code-string">"Sunset"] = class="code-string">"Sat, class="code-number">01 Nov class="code-number">2025 class="code-number">00:class="code-number">00:class="code-number">00 GMT";
            context.Response.Headers[class="code-string">"Link"] =
                class="code-string">"</api/v2/products>; rel=\"successor-version\"";
        }
    });

    Bu, istemcilere makine tarafindan okunabilir bir son tarih ve yerine geçen versiyona isaretçi saglar.

    Versiyonlu API'ler icin OpenAPI Dokümantasyonu

    Swagger/OpenAPI'yi versiyon basina ayri belgeler üretecek sekilde yapilandirin:

    csharp
    builder.Services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc(class="code-string">"v1", new OpenApiInfo
        {
            Title = class="code-string">"Products API",
            Version = class="code-string">"v1",
            Description = class="code-string">"Orijinal ürün endpointclass="code-string">'leri"
        });
        options.SwaggerDoc(class="code-string">"v2", new OpenApiInfo
        {
            Title = class="code-string">"Products API",
            Version = class="code-string">"v2",
            Description = class="code-string">"Para birimi destegi ile gelistirilmis ürün endpoint'leri"
        });
    });
    
    class=class="code-string">"code-comment">// Middleware pipeline'inda
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint(class="code-string">"/swagger/v1/swagger.json", class="code-string">"Products API v1");
        options.SwaggerEndpoint(class="code-string">"/swagger/v2/swagger.json", class="code-string">"Products API v2");
    });

    Otomatik versiyon kesfi icin `IConfigureOptions` kullanin:

    csharp
    public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
    {
        private readonly IApiVersionDescriptionProvider _provider;
    
        public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider)
            => _provider = provider;
    
        public void Configure(SwaggerGenOptions options)
        {
            foreach (var description in _provider.ApiVersionDescriptions)
            {
                options.SwaggerDoc(description.GroupName, new OpenApiInfo
                {
                    Title = class="code-string">"Products API",
                    Version = description.ApiVersion.ToString(),
                    Description = description.IsDeprecated
                        ? class="code-string">"Bu versiyon kullanim disi birakilmistir."
                        : null
                });
            }
        }
    }

    Yeni versiyon eklemek artik otomatik olarak OpenAPI belgesini üretir.

    Yaygin API Versiyonlama Hatalari

  • **Asiri agresif versiyonlama** -- her küçük degisiklik icin yeni versiyon olusturmak API yüzeyini parçalar ve bakim maliyetini katlar. Yeni versiyonlari gerçek kirici degisiklikler icin saklayin.
  • **Kullanim disi birakma takvimi belirlememek** -- kullanim disi versiyonlar sonsuza kadar kalirsa, her versiyonu süresiz bakim altinda tutarsiniz. Açik sunset tarihleri belirleyin.
  • **Endpoint'ler arasi tutarsiz versiyonlama** -- tek tek endpoint'leri versiyonlamak, dokümante edilmesi neredeyse imkansiz bir matris olusturur.
  • **Istemci tarafindaki etkiyi unutmak** -- SDK'lar, istemci kütüphaneleri ve entegrasyon testleri de hangi versiyonu hedeflediklerini takip etmelidir.
  • **Versiyon numaralarini deploy döngüsüne baglamak** -- API versiyonlari sözlesme degisikliklerini temsil eder, sürüm döngülerini degil.
  • **Versiyon kesfini ihmal etmek** -- istemciler mevcut versiyonlari programatik olarak bulamazsa, kaçinilmaz olarak yanlis versiyonu çagiracaklardir.
  • Sonuc

    API versiyonlama güvenle ilgilidir. Teknik uygulama, degisiklikleri net iletme ve versiyonlari sorumlu bir sekilde emekliye ayirma konusundaki kurumsal bagliliktan daha az önemlidir. Ekosistemine uyan bir sema seçin, dokümantasyonu otomatiklestirin, sunset tarihleri belirleyin ve uygulatin.

    API'leriniz icin versiyonlama stratejisi tasarliyorsaniz, uygun yaklasimi bulmanizda yardimci olabilirim.

    İlgili Makaleler

    Flutter Projeniz mi Var?

    iOS, Android ve web için yüksek performanslı Flutter uygulamaları geliştiriyorum.

    İletişime Geç