Asp.Net Core Web Api ile Gerçek Anlamda Restful Servisler Geliştirmek
Merhaba arkadaşalar, bugünkü yazım bir önceki yazımın (Restful Servisler Geliştirirken Bilmemiz Gerekenler) devamı niteliğindedir. Bu yüzden makalede Restful Servisler ile ilgili bilgi sahibi olduğunuz varsayılmaktadır. Devam etmeden önce bu konuda bir şeyler okumak isterseniz buradaki yazıma alayım.
Peki, gerçek anlamda restful servisler geliştirmek ne demek dediğinizi duyar gibiyim :) Öncelikle bu konuya açıklık getirmek istiyorum. Eminim herkes bir şekilde restful servis geliştiriyor veya az çok bilgisi var. Ancak bu servisleri geliştirirken RFC veya genel kabul görmüş standartlara ne kadar dikkat ediyoruz? İşte tam da bu noktada biz de resource’larımıza erişimi için tanımladğımız URI nasıl olmalı? Http methodlar ile nasıl ilişkilendirilmeli? Http status kodlarımızı neye göre belirlemeliyiz? Hata durumlarında consumer’larımız nasıl bilgilendirilmeli? gibi sorulara Asp.Net Core Web Api frameworkü üzerinden cevap bulacağız.
Not: Makaledeki amacım Level 2(bakınız maturity model) seviyesinde restful servisler geliştirmektir.
RFC(Request for Comment), bir konu hakkında, o konunun profesyonneleri tafından oluşturulmuş veya kabul görülmüş standarlardır. Yaptığımız iş ile ilgili yol gösterici belgelerdir de diyebiliriz. Bizde bu konu özelinde genel olarak IETF(Internet Engineering Task Force) organisazyonu tarafından oluşturulmuş RFC’ler üzerinden ilerleyeğiz. Örnek olarak HTTP için oluşturulmuş ilk RFC dökümanına buradan ulaşabilirsiniz RFC dökümanlar zamanla güncelliğini yiterebilir.
Asp.Net Core Web Api: Rest mimarisi üzerinde, restful servisler oluşturmamız için ihtiyacımız olan alt yapıyı içinde barındıran .Net envorinment içerisinde bulunan framework.
İşin formalite kısmını geçtiysek artık konuya geçebiliriz.
Bir restful servis oluşturmaya karar verdiysek öncelikle resource belirlemeliyiz. Resource’u, kısaca erişime açılmış data olarak adlandırabiliriz. Peki bu resource’a nasıl ulaşmamız gerekiyor? Rest api, resource’u adreslesmek URI kullanır. Bu konuya bir önceki makalemizde değinmiştik.
Resource Naming(Kaynak İsimlendirme) Best Practice
Resource isimlendirmesi çoğul(customers) veya tekil(customer) şeklinde olabilir. Çoğul olarak erişilmek istenirse /customers veya detay bazlı erişilmek istenirse(yani tekil olarak) /customers/{id} ile erişebilceğinden çoğul kullanılması önerilir.İsmimlendirmeye Get, Insert, Update gibi actionlar dahil edilmemelidir.
Customers için URI aşağıdaki şekilde olmalıdır.
http://www.example.com/customers
http://www.example.com/customers/{customerId}
http://www.example.com/customers/{customerId}/orders
http://www.example.com/customers/{customerId}/orders/{orderId}
URI için detaylı bilgiye ulaşmak için RFC 3986 ya bakabilirsiniz.
Çok fazla uzatmadan örnek projemize geçelim artık…
Örneği Visual Studio 2019 üzerinde .Net Core 3.1 Web Api ile geliştireceğim. Apilerimizi test etmek için Postman kullanacağım. Authors ve Books olmak üzere 2 farklı resource için CRUD işlemleri gerçekleştireceğim.
Api template’ni seçerek RestApiSample adında bir proje oluşturuyorum.
Vakit kaybetmeden projemize Author ve Book adında 2 controller ekliyoruz. Controller tipi olarak Empty seçiyorum.
Controller üzerindeki Route attirbute, bize resource erişimi için bir route belirliyor. Bu şekilde bıraktığımız takdirde api/book olarak erişime açılacaktır. Resource’u çoğul olarak isimlendirmenin genel kabul görmüş bir kural oldğundan bahsetmeiştik. Bu durumda ya Controller ismini BooksController olarak değiştireceğiz ya da dinamik olarak [Controller] ismini alması yerine resource için belirlediğimiz ismi yazmalıyız. Ben bu yöntemden ilerleyeceğim
Restfl Servislerimiz yazmadan önce dataları tutmak için gerekli yapıyı hazılıyorum. Konudan uzaklaşmamak adına bu detayları hızlıca geçeceğim.
Data yapısı için geliştirilen adımlar.
- Microsoft.EntityFrameworkCore.SqlServer ve Microsoft.EntityFrameworkCore.Tools paketleri projeye yüklendi.
- Models adında bir klasör oluşturuldu.
- Models içerisine BookLibraryContext adında bir context oluşturuldu.
- Model içerisine Entites adında bir klasör oluşturuldu.
- Entites klasörü içinde Author ve Book adında 2 entity oluşturuldu.
- BookLibraryContext içerisinde OnModelCreating methodu ovveride edilerek domainler için dumy datalar eklendi.
- Statup içerisinde BookLibraryContext register edildi.
Şimdi sıra geldi Author resource’umuz için URI belirlemeye. Action’larımızı eklemeden önce erişim için routing’lerimizi belirlememiz gerekiyor. Prefix olarak api versiyonu için api/v1 adında prefix ekliyorum. Author Controller üzerindeki Route Attibute’ini güncelliyoruz.
Akabinde tüm ve ya istenilen Author bilgisine erişmek için Get actionlarımızı ekliyoruz.
Resource’larımıza erişmek için URI ile birlikte, yapılacak işin belirlenmesi için HTTP methodlarını kullanmamız gerektiğinden bahsetmiştik.(Level 2 seviyesi için gerekli). Get işlemleri için HttpGet attribute’inden yararlandık. Ek olarak belirli bir resource’a erişmek için HttpGet attribute içerisinde {id} parametresini tanımladık.
Datalarımıza json olarak eriştik. Web api içerisinde output formatter default json olarak gelmekte.
Consumer’lar dönüş tipi olarak bekledikleri data formatını Header içerisinde Accept parametresi ile belirtmektedir. Şimdi Accept parametersi ile beklediğimiz dönüş parametresini applications/xml olarak belirtelim.
Xml olarak talep etmemize rağmen sonuç tekrardan json geldi. Web api, talep edilen data tipini desteklemediği takdirde default olarak belirlenen output data format ile dönüş yapmaktadır. Ancak bu restful servisler için doğru bir davranış değildir. Olması gereken Http status code 406 Not Acceptable olarak dönüş yapmasıdır. Bunun içn startp.cs ConfigureServices içerisinde Controller register olurken MvcOption’ı configure etmemizi sağlayan action’dan yararlanıyorum.
Şimdi tekrar deneyelim.
Sonuç tam da istediğimiz gibi. Peki diyelimki Client’larımızdan servisimizin xml’i de desteklemesi ile ilgili bir talep geldi. Bunun için IMvcBuilder için yazılmış AddXmlSerializerFormatters extensions methodundan yararlanacağız. Değişiklik aşağıdaki gibi olacaktır.
Şimdi tekrar deneyelim.
Evet artık servisimiz xml data formatını da desteklemektedir.
Belirli bir resource bilgisine erişmek için oluşturduğumuz URI üzerinden ilerleyelim şimdi. Var olan bir guid ile erişim sağlamıştık. Şimdi Random generate ettiğimiz bir guid üzerinden ilerleyelim.
Servisimiz 204 No Content Status code ile dönüş yaptı. Ancak burada olması 404 status code ile dönüş yapmasıdır. Bunun için ControllerBase içerisinde bulunan NotFound methodundan yararlanıyoruz. Action’ımızı aşağıdaki gibi güncelliyoruz.
Tekrar denediğimizde sonuç aşağıdaki gibi olacaktır.
Get işlemlerini burada noktalıyorum. Artık Insert(Post) işlemlerine geçebiliriz.
Post http methodunu resource’umuza yeni bir item eklemek istediğmiz zaman kullanılırız. Resource’umuzu Post işlemlerine açmak için oluşturduğumuz action’a HttpPost attirbute eklememiz yeterli. Bununla birlikte datayı yapılan request’in Body’isinden almak için bir object(class) oluşturmamız gerekli. Model içerisine Dtos adında bir klasör açıp AuthorCreateDto adında bir nesne oluşturup Author ile ilgili dataları almak için propery’leri ekliyorum.
Post işlemi sonucu Status Code olarak 201 Created dönmemiz gerekiyor. Bununla birlikte ilgili resource bilgilerini de dönmemiz gerekiyor. Ve son olarak Respose-Header Location field ile post edilen resource için URI bilgisini dönmemiz gerekiyor.
Tabi Asp.Net Core Web Api mühendisleri bunları göz önüne alarak bize hazır olarak ControllerBase içerisinde CreatedAtAction methodunu sunmuşlar.
Şimdi Postman ile post işlemini gerçekleştirelim. Dönen result’ı, Location ile birlikte dönen URI bilgisini ve URI bilgisi ile erişitğimiz resource bilgisini sırayla paylaşıyorum.
Post işlemini burada noktalıyorum. Var olan resource’u update etmek Put işlemine geçiyorum.
Put Http methodu resource’a yeni bir item eklemek veya var olan resource’u update etmek için kullanılırız. Put methodu ile insert işlemi uniq-key ‘in dışarıdan alındığı durumlarda yapılır. Bizde key olarak Guid seçtiğimiz için put methodu ile insert işlemi yapabiliyor olacağız.
Yeni bir item eklendiği durumda Put method, bir Post method gibi davranıp dönüş yapmak durumundadır. Eğer var olan bir resource ile işlem yapıp güncelleme yapılıyor ise 204 No Content status kodu ile dönüş yapmalıdır. Bu dönüş kodu için ControllerBase içerisinde NoContent methodu bulunmaktadır.
Öncelikle bir guid oluşturuyorum(cbebd59f-87a1–4bf1–8ded-c422bc36b951) Bu guid ile 2 defa put işlemi yapacağım. Birincisinde insert işlemi yapıp bilgileri dönecek. İkincisinde ise NoContent dönecektir. Postman ile yaptğım işlem ve sonuçları aşağıdaki gibidir.
Evet ilk request’te gördüğünüz gibi kayıt işlemi gerçekleştirildi ve status code 201 döndü. İkinci Request’te update işlemi yapıldı ve status code 204 döndü. Put http methodu için geliştirmemizi burada tamamlıyoruz. Şimdi sırada Delete var..
Delete Http methodunu da niçin kullandığımızı anlatmama gerek kalmadı sanırım :) Eğer silinmek istenen resource yok ise 404 Not Found, silme işlemi başarılı sonuçlandı ise 204 No Content olarak dönüş yapmamız gerekiyor. Delete action için kodumuz aşağıdaki gibidir.
Delete http metodu ile yapılan request/response aşağıdaki gibidir.
Book oluşturduğum servisleri uzun uzun anlatmak yerine aşağıda paylaşıyorum. Temel anlama URI bilgisi için Route attribute’inden yararlandık. Method işlemleri tıpkı Author gibi aynı şekilde devam etmekte.
Sonuç
Günümüz modern projelerinde Client-Server ilişkisi için en çok kullanılan iletişim yöntemidir Rest Servisler. .Net Environment içerisinde çalışıyorsanız Asp.net web api bunun için biçilmiş kaftandır. Ben kısaca Asp.Net Core Web Api ile neler yapacağımıza değindim. Tabi bu kadarlada bitmiyor. Detayı sizin ilginize kalmış :)
Projenin kodlarına github adresimden ulaşabilirsiniz.
Bir sonraki makalede görüşmek dileğiyle, sağlıcakla kalın.