Asp.Net Core Web Api Versiyonlama ve Swagger Entegrasyonu

Adem Olguner
Devops Türkiye☁️ 🐧 🐳 ☸️
7 min readFeb 25, 2024

Teknolojik gelişmeler genellikle bir ihtiyacı karşılamak amacıyla ortaya çıkar. Geliştiriciler olarak, bu teknolojileri sıklıkla kullanırız; ancak, çoğu zaman neden ortaya çıktığı, hangi ihtiyaca hizmet ettiği, neyi kolaylaştırdığı veya hangi sorunu çözdüğü gibi temel soruları sormaya odaklanmayız. Her çıkan yeniliği projenin gereksinimlerine uygun mu diye sormak ve kullanılmasının artı ve eksilerini değerlendirmek zorundayız. Bu soruları sormadan yapılan her entegrasyon veya geliştirme, genellikle beklentilerin altında kalır ve uzun vadede olumsuz sonuçlar doğurabilir. Bu nedenle, her teknolojiyi kullanmadan önce bu sorgulama sürecini geçirmek, projelerin başarıya ulaşması için kritik bir öneme sahiptir. Tecrübe ile sabittir!

Gelelim sorularımıza ve bu sorulara verebileceğimiz cevaplara.

  • Versiyonlama nedir ?
  • Neden versiyonlama kullanmalıyız?
  • Versiyonlama için hangi stratejileri yada yöntemleri bulunmaktadır?
  • Sorularımız bu şekilde uzayıp gider.

Versiyonlama Nedir?

Versiyonlamaya geçmeden önce biraz web api’lerden konuşalım kısaca.

Web Api nedir? Neden kullanılır?

API, Uygulama Programlama Arayüzü’nün kısaltmasıdır. Basit bir ifadeyle, API, birbirinden ayrı iki farklı yazılım bileşeninin belirli tanımlar ve protokoller aracılığıyla iletişim kurmasını sağlayan bir arayüzdür. Bu iki farklı yazılım birimi arasındaki etkileşimi kolaylaştırır.

Ancak, bir API’nin hizmet verdiği uygulamalar sadece iki bileşenle sınırlı olmayabilir. Hizmet veren API’nin N adet tüketicisi olabilir. Bu durumda, belirli standartlarda hizmet vermek ve yapılan herhangi bir değişiklikten etkilenmeksizin hizmetin devamlılığını sağlamak önemlidir.

Bu noktada, API versiyonlaması devreye girer. Versiyonlama, tüketicilere hizmet sunma sürecini yönetmenin ve yeni güncellemeleri sorunsuz bir şekilde uygulamanın bir yoludur. En basit haliyle, versiyonlama, değişiklikleri uygulayarak ve yeni özellikleri tanıtarak hizmeti güncel tutma yöntemidir. Bu, hizmet verenin sunduğu hizmetin sürekli geliştirilmesini ve aynı zamanda mevcut tüketicilerin hizmetten etkilenmemesini sağlar. Versiyonlama, API’lerin neden ve nasıl geliştirildiği konusunda önemli bir anahtardır.

Versiyonlama apilerin farklı sürüm veya versiyonlarının yönetilmesidir.

Neden versiyonlama kullanmalıyız

Yazılım yaşam döngüsü içinde öngörülerin de bir sınırlılığı vardır. Başlangıçta API tasarlanırken, mümkün olan her senaryoyu düşünmeye çalışabiliriz. Ancak süreç içinde ihtiyaçlar, çıktılar, hata kodları ve iş kuralları gibi varsayımlardan kaynaklanan değişiklikler, farklı bir versiyona geçme ihtiyacını doğurabilir. Yazılım dünyası, değişim kavramının sürekli var olduğu bir ortamdır. SOLID prensipleri içinde yer alan “Open-Closed” prensibi, başlangıçta tasarlanan mimarinin değişikliklere uygun olarak yazılmasını önerir. Ancak, bu derin konuya girmeyeceğim ve Solid prensipleri hakkında daha fazla bilgi almak isteyenler için,Batuhan güngör kaleminden okuyabileceğiniz solid-part-1 ve solid-part-2 yazılarını önerebilirim.

  1. Gelişen İş İhtiyaçları: Bir web API başlangıçta belirli bir iş ihtiyacını karşılamak üzere tasarlanabilir, ancak iş ihtiyaçları zaman içinde değişebilir. API versiyonlamak, yeni gereksinimlere uyum sağlamak ve iş mantığındaki değişikliklere adapte olmak için esneklik sağlar.
  2. Müşteri Talepleri ve Geriye Dönük Uyumluluk: Müşterilerin veya uygulama kullanıcılarının ihtiyaçları da zamanla değişebilir. Web API versiyonlaması, mevcut müşteri tabanının taleplerini karşılamak ve geriye dönük uyumluluk sağlamak amacıyla kullanılır.
  3. API’yi Kullanan İstemcilerin Çeşitliliği: Farklı uygulamalar, cihazlar veya istemci türleri, API’yi kullanırken farklı özelliklere veya veri yapılarına ihtiyaç duyabilir. Versiyonlamak, farklı istemcilere uygun API sürümlerini desteklemek için kullanılır.
  4. Hata Düzeltmeleri ve Güvenlik Güncellemeleri: API’lerdeki hata düzeltmeleri ve güvenlik güncellemeleri zamanla gerekebilir. Bu tür değişiklikler, mevcut kullanıcılar ve uygulamalar üzerinde olumsuz etkilere yol açabilir. Versiyonlama, bu güncellemeleri uygulamak ve güncellenmiş API’yi kullanmak isteyenlere esneklik sağlar.
  5. API’nin Genişlemesi ve Yeniden Tasarımı: API’nin başlangıçta küçük bir hedefle oluşturulması ve zaman içinde genişlemesi durumunda versiyonlama gerekebilir. Ayrıca, API’nin temel tasarımında veya mimarisinde yapılan önemli değişiklikler için versiyonlamaya ihtiyaç duyulabilir.
  6. Test ve Geliştirme Süreçleri: Yeni özellikleri test etmek ve geliştirmek isteyen geliştiriciler, mevcut API sürümüne zarar vermeden yeni özellikleri eklemek isteyebilir. Bu durumda versiyonlama, geliştirme süreçlerini daha güvenli ve etkili hale getirir.

Versiyonlama, API’lerin uzun vadeli sürdürülebilirliği, uyumluluk ve güncelleme ihtiyaçlarına uyum sağlamak için önemli bir stratejidir. Ayrıca, bu yaklaşım, hem API sağlayıcıları hem de kullanıcıları için daha iyi bir deneyim sunar.

Versiyonlama için hangi yöntemleri bulunmaktadır?

Burada neden ve niçin sorularının ardından versiyonlamayı kullanırken hangi standart ve strateji ile kullanabiliriz bunu inceleyelim.

Web Api versiyonlama işlemleri için kullanılan stratejiler:

  • URL
  • Query String
  • Header/Media Type

Versiyonlama stratejilerine geçmeden önce, küçük bir soru ile devam etmek istiyorum. API versiyonlaması yaparken kullanılacak numaralandırma konusunda varsayılan bir versiyon var mıdır? Ayrıca, versiyonlama sürecinde yapılan güncellemeleri hizmet verdiğimiz istemcilere nasıl bildirebiliriz? Bu sorular, kodlarımızı yazarken bu konuları nasıl ele alacağımızı incelememiz için önemlidir.

Kısa örnekler ile belirtip uygulama üzerinde her tanım parametresini inceleyerek devam edeceğiz. Neyi neden kullanıyoruz sorgulayıcı bakış açısını sürdüreceğiz :)

Bu stratejilerin her biri için artı ve eksi tarafları bulunmaktadır. Değerlendirilip yerine göre kullanabiliriz.

Bu yöntemlere ek olarak action seviyesinde de versiyon belirleyebiliriz. Bu işlemi MapToApiVersion attribute ile yapılandıracağız.

Let’s code

Web Api projesi oluşturalım.

Uygulamaya Nuget Paket eklentisi yada terminalden bu 2 paketi yükleyelim.

dotnet add package Microsoft.AspNetCore.Mvc.Versioning
dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer

Program.cs dosyasında AddApiVersioning ekleyelim. Bu işlem neticesinde artık uygulamamıza versiyonlama servisi yüklenmiştir.

builder.Services.AddApiVersioning();

Api uygulamasını ayağa kaldırmaya çalıştırdığımızda bir şeyler ters gitti “An API version is required, but was not specified” default version belirtilmediği hatası aldık.

{
"error": {
"code": "ApiVersionUnspecified",
"message": "An API version is required, but was not specified.",
"innerError": null
}
}

Default Api VersiyonTanımlamları

Program.cs dosyası üzerinde builder.Services ile başlayıp devam eden noktada kod karmaşasını önlemek adına versiyon işlemleri için ayrı bir class ve ayrı bir metot(AddVersionConfigure) üzerinden devam edeceğim.

public static IServiceCollection AddVersionConfigure(this IServiceCollection services)
{
services.AddApiVersioning(opt =>
{
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.AssumeDefaultVersionWhenUnspecified = true;
});

return services;
}

Varsayılan api versiyonunu belirliyoruz. DefaultApiVersion tanımını yapıp AssumeDefaultVersionWhenUnspecified tanımlamasını yapmadan veya false olarak ayarladığımızda yine aynı hata ile karşılaşacağız. Bu durumda true olarak ayarlamanız gerekmektedir. Herhangi bir versiyon belirtilmediği durumda versiyonu 1.0 olarak belirlemiş oluyoruz.

AssumeDefaultVersionWhenUnspecified = true;

Desteklenen Sürümlerden Haberdar Etme

Peki uygulamızın hangi versiyonda veya versiyonlarda çalıştığını bilgisini istemcilere nasıl haber vereceğiz?

ReportApiVersions = true

ReportApiVersions parametresini true olarak belirtiyoruz. Controllerda herhangi bir versiyon eklemeden uygulama ayarlarında bu bilginin setlenmesi ile api hangi versiyon veya versiyonlara destek verdiğini eklemiş oluyoruz.

public static IServiceCollection AddVersionConfigure(this IServiceCollection services)
{
services.AddApiVersioning(opt =>
{
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ReportApiVersions = true;
});


return services;
}

Controller nesnesinde herhangi bir ek versiyon belirtmeden default olarak ayarladığımız versiyon bilgisi Header içerisinde iletmiş oluyoruz.

ReportApiVersions : Api-Supported-Versions

Birden fazla versiyon ekleyerek buradaki bilginin nasıl görüntülendiğine bakalım. Article controller ApiVersion attribute ile versiyonlari ekleyelim.

[ApiController]
[Route("api/[controller]")]
[ApiVersion("1.0")]
[ApiVersion("1.1")]
[ApiVersion("1.2")]
[ApiVersion("1.3")]
public class ArticleController : ControllerBase
{

[HttpGet]
[Route("id/{id}")]
public Task<IResult> GetAsync(string id)
{
var allProducts = MockArticle
.GetDatabaseExampleModels();

var response = allProducts
.FirstOrDefault(c => c.Id == id);

return Task.FromResult(Results.Ok(response));
}

[HttpGet]
[Route("list")]
public Task<IResult> GetListAsync()
{
var allProducts = MockArticle
.GetDatabaseExampleModels()
.OrderBy(d=>d.OrderValue);

return Task.FromResult(Results.Ok(allProducts));
}
}

Api-Supported-Versions ile eklediğimiz ve hizmet verdiğimiz versiyon bilgilerini iletmiş olduk.

ReportApiVersions

Versiyonlama Stratejileri

Api versiyonunu client tarafının okuyabilmesi için farklı yöntemler bulunmaktadır. Bu yöntemleri ApiVersionReader özelliği ile belirtiyoruz. Bir veya birden fazla yöntemle kullanabileceğimizi söyleyebiliriz konfigürasyonu buna göre yapılandırabiliriz.

public static IServiceCollection AddVersionConfigure(this IServiceCollection services)
{
services.AddApiVersioning(opt =>
{
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ReportApiVersions = true;
opt.ApiVersionReader = ApiVersionReader
.Combine(
new UrlSegmentApiVersionReader(),
new QueryStringApiVersionReader(),
new HeaderApiVersionReader("x-api-version"),
new MediaTypeApiVersionReader("x-api-version")
);
});


return services;
}

1- URL ile versiyon belirleme — UrlSegmentApiVersionReader

Apinin versiyonu url üzerinde belirtilir. Controller route işlemi ile belirtebiliriz. Bu yöntemde url ile versiyon bilgisi bir bütün şeklindedir. Yeni versiyon hizmete girdiğinde client istek attığı url bilgisini güncellemesi gerekecektir. Bu yöntem kendi içerisinde aslında bir ihlal olarak görülebilir. Versiyon güncellemesinde tüketicinin endpoint bilgisinide değişmesini gerektireceğini unutmamalıyız.

[Route(“api/v{version:apiVersion}/[controller]”)]

https://webapi.practice.com/api/v1/articles
https://webapi.practice.com/api/v2/articles

2- Query String ile versiyon belirleme — QueryStringApiVersionReader

Query parametresi ile versiyon bilgisi iletilir. Url de api-version=1.0 şeklinde ayarlanarak istek atıldığında hangi versiyona yönleneceğini anlayabiliriz.

https://webapi.practice.com/api/articles?api-version=1.0
https://webapi.practice.com/api/articles?api-version=2.0

QueryStringApiVersionReader() default olarak “api-version” parametre ismi ile gelmektedir. Bunu istediğimiz zaman özelleştirebiliriz.

QueryStringApiVersionReader(“my-api-version-key”)

QueryString versiyonlama Url versiyonlama işlemine nazaran daha esnek görünmektedir. Url olarak tek bir url bilgisi kullanmaktadır.

3- Header/Media Type ile versiyon belirleme — HeaderApiVersionReader

Header da gönderilen parametre ile versiyon belirtilir. Burada da yine aynı şekilde kendi belirleyeceğimiz key değeri ile api versiyon bilgisini alabiliriz. Bu yöntem ile url bilgisinin v1,v2 versiyonlama url değişimi ve query string karışıklığınında önüne geçmektedir.

GET /articles HTTP/1.1
Host: webapi.practice.com
Accept: application/json
Api-Version: 1.0
GET /articles HTTP/1.1
Host: webapi.practice.com
Accept: application/json
Api-Version: 2.0

Yine aynı şekilde konfigürasyon ile bu api-version anahtarı yerine geçecek farklı bir anahtar ile de versiyon bilgisini kullanabiliriz.

new HeaderApiVersionReader(“my-api-version-key”),
new MediaTypeApiVersionReader(“my-api-version-key”))

MediaTypeApiVersionReader kısmı ise yine header da gönderilen Content-Type veya Accept parametresinin içerisinde de x-api-version değerini gönderilerek versiyon bilgisine ulaşılabilir uygulama istenilen versiyonda çalışacaktır

      URL -> https://webapi.practice.com/api/v1/metod
Header -> x-api-version:1.0
MediaType -> Accept/Content-Type: application/json; x-api-version=1.0

Bu stratejilerin her biri için artı ve eksi tarafları bulunmaktadır. Değerlendirilip yerine göre kullanabiliriz.

Swagger ile Asp.Net Core Api Versiyon Konfigürasyonu

Swagger entegrasyonu için ufak dokunuşlar yapacağız. AddVersionedApiExplorer metodunu konfigürasyonunu yapalım.

services.AddVersionedApiExplorer(setup =>
{
setup.GroupNameFormat = "'v'VVV";
setup.SubstituteApiVersionInUrl = true;
});

GroupNameFormat: Versiyonlama için apilerin grup isim formatını belirtir. 'v'VVV formatı kullanılarak grup isimleri "v" öneki ile versiyon numarasını içerecek şekilde oluşturulur.

Burada ‘v’VVV olarak tanımlayıp proje içerisinde farklı isimlendirme ile klasör oluşturduğumuzda ve çalıştırmak istediğimizde hata alıyor olacağız.

Ek olarak buradaki grup isim tanımını biraz özelleştirebiliriz.
setup.GroupNameFormat = “‘v’VVV” =>> “‘adem-api-version-v’VVV”

Url route değişmeyecektir sadece swagger UI tarafında bu şekilde görüntülenecektir.

SubstituteApiVersionInUrl: API versiyonunu URL'de otomatik olarak yerine koyacak şekilde ayarlanır. Örneğin, /api/v1/article gibi bir URL oluşturulmasını sağlar.

Bu makalede dikkati çekmek istediğim nokta versiyon işlemi, swagger ile daha fazla yazıyı uzatmak istemediğim için detay giremiyorum. Swagger entegrasyon detayları için projeyi buradan indirip inceleyebilirsiniz.

Bu yazınında sonuna geldik, asıl amaç sorgulama ve cevap bulmaya çalışmak bu alışkanlığı önce kendimde sonra siz değerli okuyuculara pratik etmeye çalışıyorum. Umarım faydalı olmuştur.

Farklı bir yazıda görüşmek dileği ile.

Saygı ve sevgilerimle
Adem OLGUNER

--

--