Caner Tosuner

Leave your code better than you found it

Web API İçin 5 Altın Kural

Çoğu zaman yazılım geliştirirken ortaya çıkan ürün yazılımcılar için değilde son kullanıcılar içindir ve bu kişiler teknik olmayan ve sadece UI tarafıyla haşır neşir olan kişilerdir. Ortaya çıkan ürünün iyi bir arayüzü vardır ve son kullanıcı arkada çalışan hangi teknolojiymiş, nasıl çalışıyormuş gibi bilgilerle hiç ilgilenmezler.

Ancak WebApi için bunu söyleyemeyiz. Yazılımcı olarak geliştirmiş olduğunu WebApi projesi end-user için değil bazen kim olduğunu bilmediğimiz başka yazılımcılar içindir. Bu kişiler teknik bilgisi en azından junior developer seviyesinde olan kişilerdir ve ortaya çıkan ürünün interface'i değilde yazılım tarafında ki her bir ince detayı inceleyip kullanacak olan kişilerdir ve sizi eleştirme hakkına da sahiptirler. 

Api'ı kullanacak olan kişiler yazılımcılar olduğundan geliştirmeyi yaparken bir WebApi client'ıymış bakış açısıyla yaklaşıp öyle geliştirme yapmak gerekir ve aslında bir nevi bu bakış açısını da Api'ı kullanan kişilerle de paylaşmış oluyoruz.

Api geliştiriciler genelde geliştirme sırasında şu sorulara odaklanırken ;"Bu servisin ne yapması gerekiyor ?", "Bu servis metodu ne sağlamalı ?", "Content-type json mı, xml mi ?" etc. , Api'ı kullanan kişiler "En az efor sarf ederek bu Api'ı nasıl kullanırım ? etc".

Görüldüğü üzre Api'ı yazan ve Api'ı kullanan kişiler tamamiyle farklı şeylere odaklanıyorlar çünkü farklı bakış açılarıyla Api'ı kullanıyorlar.  Sonuç olarak Api'ı yazan kişiler olarak uygulamayı geliştirirken consume edecek kişilerin yani Api kullanıcılarının bakış açısından bakıp onlar bu APi'ı kullanırken ne gibi sorular sorabilir veya hangi sorunun cevabına en kolay şekilde ulaşabilirler bunu düşünerek hareket etmemiz gerekir.

Peki iyi güzel ama böyle bir Api geliştirmek için neler yapmak gerekir ? Bunun için birçok geliştirici tarafından standart kabul edilen 5 altın kural vardır;

  1. Documentation (Dökümantasyon)
  2. Stability and Consistency (Kararlılık ve Tutarlılık)
  3. Flexibility (Esneklik)
  4. Security (Güvenlik)
  5. User Acceptance (Kullanıcılar tarafından kabul görmesi)

Rule 1: Documentation 

Yazılım geliştiren kişilerin ortak pek sevmediği şeylerden biri sayfalarca analistler tarafından yazılmış dökümanları okumaktır. Sizde sevmiyorsunuz dimi ?.. :)  

İyi bir dökümantasyon Api için olmazsa olmazlardandır ve çoğu zaman Api'ları geliştirren kişiler olarak bu iş biz developer'lara bırakılmıştır. Kullanıcı tarafından düşünelim bir bankada çalışıyorsunuz ve banka radikal bir karar alarak bazı servislerini dışarıya açma kararı aldı ve başladınız Api metodlarını yazmaya. Api'lar prod'a alınıp kullanıma sunulduktan sonra kullanmak isteyen kişilerin ilk başlayacakları yer Api ile ilgili yazılan dökümanları okumaktır.  Yani birinin sizin Api'ınızı kullanmasını istiyorsanız ilk yapmanız geren şey dökümantasyon yazmaktır çünkü kullanıcıların ilk bakacakları şey budur.

Peki iyi bir dökümantasyonu nasıl yazarız ?

Yazılımla projeleri ile ilgili dökümanlarda genelde; hangi sırasıyla metodların çağrılacağı, metod parametreleri, değişken tipleri, request, response class'ları etc. ve dökümantasyon oluşturmak içinde bir çok tool'da bulunmaktadır aynı zamanda kendimizde bunları basit bir template belirleyerek yazabiliriz. 

Ancak harika yazılmış bir dökümanı üstte bahsettiğimiz yaygın olarak kullanılan döküman yazma tekniklerinden ne ayırır diye soracak olursa Api'ın kullanım örnekleri ve iyi bir eğitim içeriği. Bu ikisi Api'ı kullanan kişiler için en önemli iki şeydir diyebiliriz çünkü son kullanıcı için gerçek bir örnek üzerinden ve takıldığı noktaları eğitim içeriğine bakarak en hızlı ve kolay şekilde öğrenecektir. Ancak yazdığımız dökümanın şeması ve yazdığımız örnek kodların karmaşık olmamasına da dikkat etmeliyiz. Döküman yazıyoruz diye kullanıcıya 300 sayfalık bir roman veya 15 class'lık bir örnek projede yazmamalıyız :)

Dökümantasyon işiniz bittikten sonra yapabiliyorsanız yapmış olduğunuz örnek Api kullanım projelerini ve dökümanları çevrenizdeki developer'lara gönderin ve feedback'ler almaya çalışın. Gelen feedback'ler doğrultusunda da yazmış olduğunuz dökümanıdaha user-friend hale getirebilirsiniz.  

Yaptıkları dökümanları harika bulduğum birkaç firma var ki bunlar kendi sektörlerinde en iyiler bile değiller ancak gerçek bir Api dökümanı nasıl olmalı sorusuna verilecek en iyi cevabı vermiş firmalar;

 

Rule 2: Stability and Consistency

Daha önce Facebookûn Api'larını kullandıysanız ne sıklıkla Api'ları değiştirdiklerini bilirsiniz. Sürekli olarak bir güncelleme yayınlıyorlar ve çalışan birçok uygulama da patlıyor çatlıyor. Facebook'un ne kadar başarılı bir ürün olduğuna herkes hemfikirdir ancak başarılı olmalarının sebebi son derece iyi bir Api'a sahip oldukları değil milyarları geçen kullanıcı sayısı sahip olmaları ancak iş Api konusuna gelince developer'lar için bazen hayatı zindan ettikleri oluyor. Muhtemelen sizlerin geliştirdiği Api'lar milyarlarca kullanıcı tarafından kullanılmicak ancak o bakış açısıyla geliştiriyor olmakta fayda var. Yeni sürüm yayınladığınızda eski versiyonlara desteği en azından birkaç yıl daha sürdürüyor olmak gerekir en azından mevcut kullanıcıları en iyi şekilde yeni versiyondan haberdar ederek onların yeni versiyona geçmelerini sağlamak gerekir.

Örnek üzerinden gitmek gerekirse ; farz edelim ki http://www.canertosuner.com/api/getUsers/  şeklinde tanımlı JSON formatında response dönen ve yaklaşık 10 bin kişi  tarafından kullanılan bir Api'ımız var diyelim. Api'ı production'a aldıktan aylar sonra dönen responsları değiştirdiniz ve bu Api'ı kullanan kişileri de etkileyen bir değişiklik olsun. Bu şu demek; 10 bin kişinin geliştirdiği 10 bin uygulamaların patlaması demek. Bunun çözümü tabii ki de uygulamaya yeni versiyon çıkmamak değil bir ürün aldığı update'ler ile daha iyi olur. Bunun çözümü için Api'ınıza basit bir versiyon kontrolü koymak ve eski versiyonlara desteği sürdürmek.( http://www.canertosuner.com/api/getUsers?version=2 yada http://www.canertosuner.com/api/v2/getUsers ) .Böylelikle hem eski versiyonu kullananlar yeni versiyona geçene kadar uygulamalarının çalışmalarını sağlayabilirler hemde Api'ı yeni kullanmaya başlayacak olanlar direkt olarak son versiyondan başlarlar.

Api'ınızın Consistent yani tutarlı olması da son derece önemlidir. Api'ınızın geriye döndüğü response class'larının ortak bir base class içerisinde olmasına özen gösterin. Çünkü bu class sayesinde metodun döndüğü response dışında Api kullanıcısına farklı verilerde döndürebilirsiniz. Daha önce kullanmış olduğum bazı Api'larda tutarlılık neredeyse hiç yoktu. Sürekli olarak yeni gelen versiyonlarda parametre isimleri değişiyor, metod isimleri değişebiliyor, bir önceki metodda UserID'yi int gönderirken bir sonraki metodda string olarak istiyorlardı, hata mesajları sürekli olarak farklı formatta geliyordu vs. gibi örneklerle karşılaşmak mümkün. Bu gibi durumlara dikkat etmek gerekiyor. Ortak kullanılan parametreler tek bir yerden yönetilebiliyor olmalı ve major değişiklikler kolay kolay uygulanmamalı veya uygulandığında Api'ı kullanan kişiyi etkilenmesinden kaçınılmalı.

 

Son olarak yayınlamış olduğunuz yeni versiyonlarda iyi bir changelog yayınlayıp mevcut kullanıcılarınızı bilgilendirmeniz gerekir. Böylece kullanıcılar nasıl upgrade edeceklerini öğrenmiş olurlar ve Api uygulamanızda çok büyük major değişikliklere gitmemeye özen gösterin veya bunu kullanıcıları en az seviyede etkileyecek şekilde yapın ve tutarlılığı korumaya çalışın.

 

Rule 3: Flexibility

Yazmış olduğumuz Api'ların flexible yani esnek olması oldukça öçnemli bir konudur.Peki ama esnek derken neyi kastediyorum ?

Garbage in, garbage out (GIGO) programcılar tarafından iyi bilinen bir technical-term dür. Kısaca "input olarak ne verirsen output'un ona göre değişiklik gösterir" veya ne ekersen onu biçersin". Hadi biraz daha basit söyleyelim programa yanlış bir request'te bulunursanız response'unuzda yanlış olacaktır. GIGO yu örnek olarak vermemin sebebi aslında Web Api tarafında request response ilişkisine dikkat çekmek istemem. 

Günümüzde bir çok Api doğru düzgün bir JSON desteği bile bulunmamakta ancak iyi bir Api'ın sadece JSON değil bunu yanında YAML, XML vs. gibi formatlar içinde desteği bulunmalıdır ve bunlardan hangisini return edeceği bilgisini de aslında Api kullanıcılardan yani client'lardan parametre olarak almalıdır. Örnek olarak http://www.canertosuner.com/api/getUsers?Format=JSON yada bu bilgiyi header'a parametre olarak eklemek aslında en doğru kullanımdır diyebiliriz Accept: application/json .

Bu kullanım sadece kullanıcıya dönecek olan response için değil aynı zamanda kullanıcının size göndereceği Post metodlarında body de bulunan request parametreleri içinde geçerlidir. Bir kulalnıcı JSON olarak gönderirken diğer bir kullanıcı XML olarak göndermek isteyebilir ve böyle bir esnekliğe sahip olabilmek oldukça önemli bir ayrıcalıktır.

Api'ınızın OData özelliğine sahip olması da bir o kadar önemlidir. OData ile Api'nızın döneceği respons'lara kullanıcılar tarafından filtreleme yapma şansı sunarsınız ve böylece kullanıcının istemediği bir veriyi dönmemiş olursunuz. Örneğin A kullanıcısı GetProducts metodundan sadece ProductID'lerini almak isterken B kullanıcısı ProductName ve ProductID alanlarını almak isteyebilir. OData bu gibi durumlar için son derece filexible(esnek) bir kullanım sunar.

 

Rule 4: Security

Güvenlik bir WebService & WebApi projesindeki en önemli noktalardan biri ancak öyle Api'lar var ki otantike olmak nerdeyse bazen imkansız oluyor. Tamam güvenlik önemli ama öyle katı ve karmaşık kurallar koyarak Api yazan firmalar var ki bazen birbiri ile ilişkili Api' metodları için 2-3 çeşit güvenlik algoritması kullandığımız olabiliyor ve ortada dökümanda yoksa nasıl requestte bulunacaksın, nasıl response alacaksın hepsi belirsiz. Bir Api developer olarak Api'ı kullanan kişiler için nasıl authenticate ve authorize olunur bilgilerini içeren kolay ve açıklayıcı örneklerle anlatıyor olmamız gerekir. 

Günümüz Web Api'larının çoğunda ortak olarak token-based authentication kullanılmakta. Kısaca; kullanıcı yapmış olduğu ilk requestte Api'a bazı güvenlik parametreleri geçer ve Api'da ona random generate edilmiş olan token bilgisini döner ve client bütün session'ı boyunca aynı token üzerinden request atıp response almaya devam eder. 

Token dışında OAuth 2 + SSL de Api'ınızı güvenli hale getirmek için yapılabilecek diğer seçenekler arasındadır. SSL her halükarda kullanıyor olmamız gerekir bunun yanında OAuth 2'yi de server-side'da uygulamakta oldukça basittir ve  OAuth 2'nin hemen hemen bütün yaygın kullanılan programlama dilleri için kütüphaneleri de bulunmaktadır.

Bunlarla birlikte güvenlik için dikkat edilmesi gereken birkaç konu dha bulunmaktadır;

  • Api'larda genellikle update, insert, delete gibi işlemler yapılabilmektedir. Bu işlemleri yapan metodları public hale getirip bütün kullanıcıların kullanımına sunarken dikkat edilmesi gerekmektedir. Her kullanıcının şöyle bir Api çağrısı yapamıyor olması gerekir "/user/delete/<id>" . Bununla ilgili her bir kullanıcı için Whitelisting Functionality bilgisi oluşturup bu listede belirtilen kurallara göre request validation işlemleri yapılabilir. 
  • OData kullanırken de select işlemleri yapılırken kullanıcının sahip olmasını istemediğimiz bilgiler için request'te bulunduğunda 406 Not Acceptable Response şeklinde status kodlar dönebiliriz. 
  • Cross-Site Request Forgery (CSRF) isteklerine akrşı Api'ı korumalıyız. Session veya cookie bazlı bir authentication yapımız var ise Api'ımızı CSRF ataklarına karşı koruduğumuzdan emin olmalıyız. Bununla ilgili faydalı dökümanları The Open Web Application Security Project (OWASP) da bulabilirsiniz. 
  • Resource dosyalarına olan erişimi yönetiyor olmamız gerekir. Örnek olarak bir banka kredi kartlarını tutan Api yazdınız ve Api içerisindeki bir dosyada kredi kartı görselleri bulunmakta. Herhangi bir kullanıcı gidipte  /account/card/view/152423 şeklinde bir istekte bulunup erişmemesi gereken bir resource dosyasına erişmemelidir.
  • Bütün request'leri validate ediyor olmamız gerekir. Her bir request'in kendine özgü parametreleri bulunur ve kullanıcı sürekli olarak saçma sapan request'lerde bulunduğunda örnek olarak; userId miz 4608 olsun ve user bilglsini getiren metoda 4608 den başlayıp random sayılar üreterek ( /account/getUserInfo/4609) başka kullanıcıların bilgileri için request'te bulunduklarında Api'ımızın bir şekilde bir güvenlik kontrolü olup bu kullanıcıyı tespit edip engellemelidir.

 

Rule 5: User Acceptance

Beşinci ve son kural aslında bu beşli arasındaki en önemli kural diyebiliriz. Bu kural ilk 4 kural boyunca bahsettiğim bütün şeylerin aslında bir ürün olarak hazırlanıp kullanıcıya sunulması ve kabul görmesini içermekte. Örneğin iyi bir dökümantasyon, kolay entegre edilebilir güvenlik adımları, yazdığımız Api'metodlarını tutorial'larla süsleyip max 15 dakikada kullanıcılar tarafından entegre edebilmelerini sağlama gibi durumlar diyebiliriz.

Api'ın kullanıcılar tarafından daha kolay kabul görmesini sağlayacak bazı spesific tavsiyeler saymak gerekirse;  

  • Kullanıcıların dökümantasyonda belirtilenlere göre Api'ınızı ilk denemeden sonra entegre edebildiğinden emin olun.
  • KISS - Keep it Simple Stupid anlayışına göre hareket etmeye çalışın. Fantastik authentication yöntemlerinden kaçının, SOAP, JSON, REST'i yeniden yaratmaya çalışmayın veya bütün platformlar tarafından kabul görmemiş herhangi bir yöntem kullanmayın.
  • Service arayüzü için dil spesifik library'i desteği vermeye çalışın. Otomatik olarak bu işlemi yapan güzel tool'lar da mevcut (Alpaca veya Apache Thrift gibi).
  • Gereken sign-up işlemlerini en basit şekilde yapın. Api'ınız bir open-source proje değilse ve sign-up & register gibi işlemler varsa bunları olabildiğince basite indirgeyip biran önce kullanıcıları yormadan api'ınınzın bulunduğu yere yönlendirin. Eğer sizin için extra bir maliyeti yoksa sign-up with social media account (facebook, google, twitter etc) özelliği sunabilirsiniz. 
  • "Satış sonrası destek" sağlayın. Bug'sız uygulama olmaz ve Api'ı kullanan kişiler bug veya herhangi bir sorun ile karşılaştıklarında en kısa ve kolay şekilde bunları size iletmesini sağlayın. Bu bir forum sitesi veya e-mail sistemi olabilir size kolayca raporlayabilsinler. Sorunu giderip yeni versiyon çıktıktan sonrada ilgili kişileri tekrardan bilgilendirmeyi ihmal etmeyin.

 

Özetle..

Iot (Internet of Things) ile birlikte hayatımızda kullanacağımız IP alıp internete çıkabilen bütün teknolojik ürünler WebService & Api ile haberleşiyor olacaklar ve beraberinde birçok yeni Api'lar yazılmasına ihtiyaç duyulacak. Bugünün verilerine göre düşünürsek; binlerce api & web service var ancak sıkıntılı olan şey kullanımları gerçekten kolay değil. Sebep olarak SOLID prensiplerine pek uymayan yazılım anlamında zayıf tasarımlı projeler olması, dökümantasyon tarafının yeterli düzeyde veya yeteri kadar kolay anlaşılabilir olmaması, örnek kod parçacıkları içermemesi, raporlanmasına rağmen çözülmeyen bug'lar etc.. bir sürü sıralayabiliriz.

Yukarıda belirtilen 5 altın kural bir çok kişi tarafından aslında ortak dile getirilen başlıklar ve Api projesi geliştirirken uyulması gereken kurallar olarak belirtilmekte. Eğer bizlerde bundan sonra yazacağımız Api'larda birazcıkta olsa bu kurallara uygulayarak hareket edersek her şey hem Api geliştiriciler hemde Api kullanan kişiler için daha kolay olacaktır.

Web Api Exception Handling and Logging

Herhangi bir yazılım projesinde Exception alındığında bu exception'nın handle edilip belli başlı bazı süreçlerden geçirilip log atılmasına kadar geçen süreçler oldukça önemlidir ve enterprise bir projede development yapıyor isek ExceptionLog olmazsa olmazlardan biridir. Projeye yeni başlarken mimarisi ilk düşünülüp tasarlanması gerekir çünkü proje ilerledikçe log, exception handling veya cache gibi yapıları entegre etmek biraz daha zorlaşacaktır.

Web Api tarafında Exception handling ve log işlemleri yapmak biraz daha keyifli ve basit diyebiliriz çünkü Microsoft sağolsun bazı şeyleri bizim yerimize düşünüp kolaylaştırmış.

İlk olarak şöyle bir controller metodumuz olsun ve bu metoda requestte bulunduğumuzda ne gibi bir response ile karşılaşıyoruz onu görelim.

[HttpGet]
public IHttpActionResult CheckValue(int value)  
{
    if(value > 20)
    {
        throw new ArgumentOutOfRangeException();
    }
    return Ok(value);
}

Herhangi bir 3th party tool (DHC, Postman etc.) kullanarak ilgili metoda parametresi "10" olacak şekilde request attığımızda respose olarak göndermiş olduğumuz "10" değerini status code 200 - OK olacak şekilde döner.

Aynı requesti parametre "25" olacak şekilde attığımızda ise yukarıda fırlattığımız "ArgumentOutOfRangeException" hata açıklamasını status code 500 - Internal Server Error olacak şekilde döner.

Uygulamada controller seviyesinde bir exception aldığımızda olması gereken exception'nın handle edilip kullanıcıya doğrudan Exception class'ından fırlatılan hata mesajı değilde(ihtiyaca göre) ilgili daha anlamlandırılmış bir şekli response'a eklenip client'a dönüyor olması ve bu exception'nın log olarak bir yerde tutuluyor olması gerekir.

Yukarıda bahsettiğimiz gibi WebApi için Exception alındığında Log işleminin yapılmasını için kullanıma sunulan abstract class ve onun metodlarını inceleyeceğiz. 

1.Logging ExceptionLogger class Log metodunu kullanarak uygulamadaki herhangi bir exception'nın loglanmasını sağlayabiliriz. Bunun için aşağıda UnhandledExceptionLogger isimli class'ımızı kullanarak ilerleyeceğiz.

public class UnhandledExceptionLogger : ExceptionLogger  
{
    public override void Log(ExceptionLoggerContext context)
    {
        var log = context.Exception.ToString();
        //Loglama için ilgili ilemlerin yapıldığı yer (db log, file log vs gibi)
    }
}

Üstte tanımladığımız UnhandledExceptionLogger class'ını Web Api projesinde kullanabilmek için register etmemiz gerekmekte. Register işlemi ile birlikte WebApi nin otomatik olarak default set ettiği ExceptionLogger'ı kendi yazdığımız UnhandledExceptionLogger class'ı ile değiştiriyoruz. Bu işlem için aşağıdaki kodu Global.asax.cs içerisindeki Application_Start metoduna yazıyoruz.

config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());

 

Bu adımdan sonra uygulamada bir unhandled exception fırlatıldığı anda logger'ımız onu yakalayıp yazmak istediğimiz bir yere (db, file etc.) yazmamızı sağlayacaktır.

 

2.Excepiton Hander Bu kısımda uygulamamızda fırlatılmış olan exception'nı yakalayıp response da değiştirmek istediğimiz yerleri değiştirip client'a dönme işlemlerini yapacağız. Bunun için ExceptionHandler class'ından faydalanacağız. Bu class ExceptionLogger ve ExceptionFilter dan sonra eğer ilgili exception handle edilmediyse çağrılır. GlobalExceptionHandler ismindeki class'ımız aşağıdaki gibi olacaktır.

 public class GlobalExceptionHandler : ExceptionHandler
    {
        /// <summary>
        /// This function is used for to change the response when an exception occurs.
        /// </summary>
        /// <param name="context"></param>
        public override void Handle(ExceptionHandlerContext context)
        {
            var result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent(context.Exception.Message),
            };
            context.Result = new ExceptionActionResult(result);
        }
    }

 

Yukarıda exception fırlatıldığında yakalaıp client'a dönen response'u modify ettik. Bunun için kendi custom yazdığımız ExceptionActionResult class'ını kullanacağız. O da aşağıdaki gibi olacaktır.

    /// <summary>
    /// This class is a kind of Custom Action Result. When we get any exception and want to handle the web api method that returns HttpActionResult, we can use this class and it's functions.
    /// </summary>
    public class ExceptionActionResult : IHttpActionResult
    {
        private HttpResponseMessage _httpResponseMessage;

        public ExceptionActionResult(HttpResponseMessage httpResponseMessage)
        {
            _httpResponseMessage = httpResponseMessage;
        }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            return Task.FromResult(_httpResponseMessage);
        }
    }

 

Şimdi sırada 1.Adımda da yaptığımız gibi yazış olduğumuz Handler'ı WebApi'nin default set ettiğiyle değiştirme işlemi var bunu da Global.asax.cs içerisindeki Application_Start metodunda aşağıdaki gibi yapıyoruz.

config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());  

 

Uygulamamız hazır. Bu entegrasyondan sonra uygulamamıza 2 şey kazandırmış olduk.

  1. Exception alındığında Log atma işlemi
  2. Fırlatılan unhandled exception'ı yakalayıp kendi yazdığımız custom HttpActionResult ile değiştirip client'a giden respons'u daha anlamlı ve yönetilebilir bir hale getirmiş olduk.

Yazımızın en başında yazmış olduğumuz CheckValue metoduna veya uygulamada herhangi bir metoda request'te bulunup exception fırlatıldığında artık bütün response'lar artık şu şekilde olacaktır.

StatusCode : 500 Internal Server Error

Body : Specified argument was out of the range of valid values.

Gördüğünüz üzre projede exception alındığında log'umuzu atıp client'a dönen response'u da daha anlamlı bir hale getirmiş olduk. 

Ben örnek uygulamada response dönerken statusCode HttpStatusCode.InternalServerError yani 500 set ettim ancak siz projenizde kullanırken daha farklı statusCode'lar da ihtiyaca göre client'a dönebilirsiniz.

 

 

=> http://www.exceptionnotfound.net/the-asp-net-web-api-exception-handling-pipeline-a-guided-tour/

Web Api Projesi Oluşturma

Şöyle bir örnek proje yapalım. TodoApi adında bir WebApi projemiz olsun ve bu Api'a bir tane controller tanımlayıp içerisine TodoList dönen bir metot yazalım.

İlk olarak Visual Studio açıyoruz ve File => New => Project diyoruz ve aşağıdaki görselde olduğu gibi Web kategorisine tıklayıp sonrada ASP.Net Web Application'ı seçiyoruz ve projenize bir isim verdikten sonra OK'e tıklıyoruz.

 

Daha sonra açılam ekrandan Empty kategorisini tıklayıp ekranın orta kısmında bulunan checkbox'lardan WebApi'ı seçiyoruz ve OK'e tıklıyoruz.

 

Artık solution'da projemiz hazır. Şimdi ilk olarak Models klasörü içerisine TodoItem isminde aşağıdaki gibi bir class tanımlayalım.

namespace TodoApi.Models
{
    public class TodoItem
    {
        public string Key { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

Şimdi ise TodoController adında controller'ımızı tanımlayalım. Bunun için solution'da bulunan Controller klasörünün üzerine gelip sağ tıklayıp Add diyelim sonrasında açılan ekrandan Controller'ı seçelim ve Controller'a TodoController ismini verip OK'e tıklayalım.

Artık TodoController'ınıda oluşturduk şimdi sırada GetAllTodoItems isminde HTTPGET request'i atılabilen ve geriye List<TodoItem> dönen bir metot yazalım.

public class TodoController : ApiController
    {
        [HttpGet]
        public List<TodoItem> GetAllTodoItems()
        {
            var responseList = new List<TodoItem>
            {
                new TodoItem{
                    Key="SD2",
                    Name="Görev1",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD11",
                    Name="Görev2",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD251",
                    Name="Görev3",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD8",
                    Name="Görev4",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD01",
                    Name="Görev5",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD42",
                    Name="Görev6",
                    IsComplete=true,
                },
            };

            return responseList;
        }

Api projemiz var. Şimdi gelin bu Api'a requestte bulunup ne response dönüyor onu görelim. Projeyi çalıştıralım ve her hangi bir rest client tool kullanarak aşağıdaki link'e requestte bulunalım.

  • http://localhost/api/Todo/GetAllTodoItems

Ben genelde Postman'i kullanıyorum ve aşağıdaki gibi Postman ile GET request'i atıyoruz.

 

Dönen response'a baktığımızda aşağıdaki gibi json formatında response geldiğini göreceğiz.

 

WebApi candır arkadaşlar ve servis tarafında geliştirme yapıyorsanız da çok ama çok önemlidir. Bir Microsoft yetkilisi bir konferansta şuna benzer bir cümle kurdu "Biz daha iyisini yapana kadar en iyisi bu !".

 

Web Api Projesine Cache Ekleme - OutPutCache

Server-side tarafında geliştirme yapan arkadaşlar bilirler ki request-response time ları çok büyük önem sarf etmektedir. Örnek olarak, bir muhasebe DB niz var ve her gün gece 23:59 da günlük raporlar giriliyor veya 3 dkka yeni kayıt girilen bir yapıda olabilir. İlgili tabloda şuana kadar 200 bin kayıt girilmiş diyelim. select * from Raporlar dediniz ve size 200 bin kayıtı ortalama 15 sn de getirdi (DB nin serve edildiği Pc nin özellikleri ve network hızı gibi çeşitli etkenlere göre değişir). Aslında bu gibi yapılarda ilgili  StoraProcedure e paging parametreleri vererek daha performanslı ve hızlı bir sorgu yazabiliriz ancak bu durum için bile Cache yapısını uygulamamıza entegre edebiliriz. Şimdi bu raporları feed eden bir mobil uygulamamız, Web Sayfanız veya bir masaüstü uygulamanız olabilir ve iş ilgili uygulamanın kullanım oranına göre dakikada 100-200 request te bulunuyor olabilirsiniz. Bu uygulamalara db ile connection'ı sağlayan bir Web Api uygulamamız olsun. Şimdi yukarıda ki case de uygulamada bulunan RaporlarController 'ına dakikada 100-200 arası istek bulunmakta. Ne yapacağız peki sürekli olarak DB ye git select * from Raporlar deyip 200 bin kayıtı almak için 15 sn sürsün network vs işlemlerinden dolayı 2 sn de ordan olsun artı birde kullanıcının internet hızı kotalımı dersin :) ttnet sağolsun hızı düşürmüş 2 mb'e ve oda yaklaşık olarak 5 sn sürsün diyelim (değerler tamamiyle dummy dir). Şimdi küçük bir matematik işlemiyle ortalama kaç sn de veriyi getiriyoruz;

DB QueryResult : 15 sn

WebApi projesinin Download Süresi : 2 sn

Client uygulamasının Download Süresi : 5 sn

Client uygulamasının bu veriyi ekrana çizmeside yaklaşık 2 sn diyelim (Performanslı cihazlarda)

int[] arr = { 15 , 2, 5, 2 };
 
int sumResult = arr.Sum();
Console.WriteLine(sumResult); 
24 saniye 

Adama "Oh My God" dediğinde "Yes your god" diye cevap verirler. 

Tamı tamına 24 saniye  (biraz abartmışta olabiliriz ). Günde ortalama 100 kişinin kullandığını düşündüğümüzde her gelen 24 sn beklicek. Böyle bir projeyi al çöpe at derler adama. Benzer bir olay daha önce çalıştığım bir şirkette başıma geldi ve page_load da db ye gidip 4.600.000 kayıt için sorgu atılıyordu ve bazı işlemler yapılmaya çalışılıyordu. Projeyi bana assign edip müşteri sayfayı açamıyormuş bi bakarmısın dediler ve sorunu anladığımda yazılımdan soğmuştum diyebilirim. 

Her neyse gelelim konumuza. Projeyi bu halde bırakmayalım ama çöpede atmayalım. Projemize sağ tıklayıp nugetten WebApi OutPutCache.Core ve OutPutCache.v2 dll lerini ekleyelim.

Senaryomuz şu şekilde olacak;

1-Controller bazında hem server side için hemde client için iki tarafta da cache sağlayacak bir yapı yapıyoruz. Kullanacağımız kütüphaneye 2 parametre vericez  ServerTimeSpan  ve ClientTimeSpan .  Biri ServerSide için cache'i sağlicak yani kendine gelen ilk request'in response'ını alıp set edilen süre boyunca aynı requestle başka bir kullanıcı geldiğinde cache den alıp o yeni gelen kullanıcıya verecek. Diğeri ise ClientSide için clienta dönen response'un header'ına Cache-Control →max-age=60 eklicek. Bu şu anlama geliyor; Client'a diyor ki arkadaş ben bu respons'u 60 sn cache ledim ve sende istersen gelen response'u biyerde tutup bana 60 sn boyunca gelmeyebilirsin. 60  sn sonra tekrardan gel. Şimdi gelelim code tarafına ilk olarak WebApiCacheAttribute adında CacheOutputAttribute inherıt olan bir attribute tanımlıyoruz. Alında direkt olarak CacheOutputAttribute  controllerımızın içerisindeki metodların başına ekleyebilirdik ancak yönetimi daha kolay olur düşüncesiyle araya işimi daha kolaylaştıran WebApiCacheAttribute  adında CustomAttribute ünü yazdım.

public class WebApiCacheAttribute : CacheOutputAttribute
    {
        public ApiCacheAttribute()
            : this(WebConfigApiClientCacheDuration,WEebConfigApiServerCacheDuration){ }

          public ApiCacheAttribute(int clientCacheDuration = 0,
                                 int serverCacheDuration = 0)
        {
            base.ServerTimeSpan = serverCacheDuration;
            base.ClientTimeSpan = clientCacheDuration;
        }
    }

Üstte görüldüğü gibi bu Cache attribute'ü 2 parametre alıyor. Bu parametreleri attribute implementasyon sırasında aşağıda olduğu gibi biz değer atamaz isek WebConfig dosyasında tanımlı olan değerli alarak Cache sürelerini set ediyor.

WebConfig de appsettings de kayıtlı olan değerleri okuyarak cache işlemini yapar

[WebApiCacheAttribute]
public IHttpActionResult GetItems()
{
      var products= new IkiYuzBinKayit(); //db den 200 bin kayit getirmişiz varsayalım
      return Ok(product);
}

Ama istersek aşağıda olduğu gibi bizde bu değerleri set edebiliriz

[WebApiCacheAttribute(ApiServerCacheDuration=120,ClientCacheDuration=120)]
public IHttpActionResult GetItems()
{
     var products= new IkiYuzBinKayit(); //db den 200 bin kayit getirmişiz varsayalım
     return Ok(product);
}
 

Sonuç olarak web api projemizde cache attribute eklediğimiz metoda yapılan sorgular set edilen sürelere göre cache lenir ve o süre boyunca aynı parametrelerle gelen bütün kullanıcılara cachelenmiş olan response döner. Süreç server cache süresi bittiğinde sonlanır ve yeniden gelecek olan ilk sorgu beklenir ve döngü şeklinde devam eder.

 

Not ! Cache Cache'dir ancak hangi datanın cachelenip cachelenmemesi konusu çok ama çok önemlidir !! İyice düşünüp karar verilmesi gereken bir konudur.

Asp .Net Web Api Nedir

Daha önceki yazılarımızda Web Api dedik, Cache dedik, Exception Handling dedik ama Web Api nedir bir türlü bahsedemedik. Bu yazımızda kısaca Api & Asp.Net Web Api nedir konuşuyor olacağız.

Api Nedir ?

Asp .Net Web Api'a geçmeden önce Api nedir ondan bahsedelim. Aoi açılımı "Application Programming Interface" olan Türkçe'de uygulama geliştirme arayüzü anlamına gelir ve sahip olduğumuz service veya verileri dış dünyaya açıp başka uygulamaların-platformların kullanımına sunmak için belli kurallar çerçevesinde tanımlamalar yaptığımız arayüz dür. 

 

Asp .Net Web Api Nedir ?

Microsoft yetkilileri Web Api sunumlarından birinde şuna benzer bir şey söyledi "Biz daha iyisini yapana kadar en iyisi bu..!"

Asp .Net Web Api ise farklı türde sayısız client (browsers, mobile phones, tablets, pc, etc.) tarafından consume edilebilen HTTP protokolü üzerinden haberleşebilen servisler oluşturmak için kullanılan bir framework şeklinde tanımlayabiliriz. Asp .net MVC ile routing, controllers, action results, filter, model binders gibi ortak feature'lara sahip olduklarından bir takım benzerlikler göstermektedir ancak MVC Framework'ün bir parçası değildir. Asp .net Web Api Core Asp .Net'in bir parçasıdır ve MVC veya diğer web application türleri ile birlikte kullanılabilir. Aynı zamanda bütün bunlardan bağımsız stand-alone Web services application olarakta kullanılabilir. 

 

Neden Asp.Net We Api ?

Günümüz dünyasında teknolojini gelişmesiyle birlikte firmalar artık web tabanlı uygulamalar üzerinden müşterilerine tam olarak ulaşamaz hale geldiler. İnsanlar artık günlük hayatlarının nerdeyse %50 sini akıllı telefonlar, tablet pc vs ile geçiriyorlar ve bu cihazlarda insanların hayatlarını kolaylaştıracak olan milyonlarca uygulama mevcut. Bunların yanında birde İOT ile birlikte gelecek 5 yılda dünyada 30 milyara yakın internete bağlanabilen cihazlar olacağından bahsediliyor ve buda belki milyonlarca Api geliştirmesi demek.

Firmalar veya uygulama geliştiriciler müşterilere daha kolay ve hızlı bir şekilde ulaşmada kullanmak için servislerini ve sahip oldukları verilerin bir kısmını browserlar yada internete bağlanabilen bu akıllı cihazlar tarafından consume edilebilmeleri için Api'lar geliştirmeleri gerekmektedir. Çünkü Api'lar yapısı gereği bütün programlama dilleri tarafından ortak kabul görmüş medya tiplerini (XML-JOSN..etc.) response olarak alıp gerekli parse işlemlerinden sonra kolayca kullanabilir. 

 

Web Api sahip olduğunuz veri ve servisleri birçok farklı cihazda kullanıma sunmak için expose edebilmenizi sağlayan şahane bir framework ve dahası Web Api .Net Framework üzerinde RESTful servisler inşa etmenizi sağlayacak ideal bir open source platform. WCF Rest service'lerinin aksine Web Api HTTP protokolünün bütün özelliklerini kullanır (URIs, request/response headers, caching, versioning, çeşitli content format'ları) WCF Rest Service'lerinde yapıldığı gibi farklı cihazlar için extra config ayarları vs yapmamıza da gerek bulunmamaktadır. Request'i yapılırken dönmesi gereken response'un XML mi yoksa JSON formatında mı olacağına client'ın seçimine bırakılmıştır çünkü Web Api birden fazla medya formatında response dönebilmektedir.

 

Başlıca Web API Özellikleri

  • Http Get, Post, Put ve Delete metodlarıyla çalışabildiğinden CRUD işlemelrini destekler,
  • Response'larda HttpStatusCode ve Accept Header parametreleri bulunur,
  • Response'lar kullanıcının istediği türde MediaTypeFormatter tarafından formatlanabilir,
  • OData desteği bulunmaktadır ve Query yazması oldukça kolaydır,
  • Bir uygulama içerisinde veya IIS üzerinde host edilebilir,
  • MVC'nin bazı özelliklerini taşır (routing, controllers, action results, filter, model binders)

 

Neden Web Api'ı Seçmeliyiz ?

  • Bir web service'e ihtiyacınız varsa ve soap'a ihtiyacınız yoksa en iyi seçenek Web Api dir,
  • Geliştirme sürece WCF de olduğu kadar zahmetli ve sıkıntılı değildir,
  • Http tabanlı olduğundan Rest-ful servisler geliştirmek için en iyi seçenektir,
  • Exception ve Cache mimarileri oldukça performanslı ve yönetilebilir dir,
  • Open Source olduğundan sürekli olarak geliştirilip yeni feature'lar eklenmektedir,
  • Microsoft yetkilileri Web Api sunumlarından birinde şuna benzer bir şey söyledi "Biz daha iyisini yapana kadar en iyisi bu..!" bu demek oluyor ki tam destek.