Site icon Kod Kaynağı

REST ve RESTful Web Servis Kavramı

Modern Web mimarilerinde RESTful servisler çok yaygın bir şekilde kullanılıyor. Oldukça hafif, genişletilebilir, basit servisler. Artık SOA kullanılan projelerde de sıklıkla görülüyor. REST aslında uzun zamandır hayatımızda. Microsoft .Net Framework’e geliştirmeler yaparak istikrarlı bir şekilde REST’e yatarım yapıyor. Hatırlarsanız önce WCF’e REST mimarisi kullanan servisler geliştirmemize olanak sağlayan bir yapı geldi. Hatta en son WCF Web API isim değiştirerek ASP.NET Web API oldu, şuan beta sürecinde. Eski tarz servis uygulamaları giderek yerlerini REST tabanlı uygulamalara bırakıyorlar, bunun en büyük sebeplerinden biride gönümüz uygulamalarının artık çoğunlukla Browser tabanlı olması ve çoğu işin artık Client-Side’da yapılması, REST’in HTTP’i protokolü üzerine kurulmuş olması bu açıdan çok büyük nimet, hayatımızı oldukça kolaylaştırıyor.

Aslında ASP.NET Web API üzerine birşeyler yazmak istiyordum ama araştırma yaparken yine konunun derinliklerinde kayboldum ve kendimi REST konusunu araştırırken buldum 🙂

Daha öncede bahsettiğim gibi blog yazmanın en güzel yanlarından biriside kendinizi geliştiriyor olmanız. Bende birçok farklı kaynaktan edindiğim bilgileri toparlayarak, REST hakkında fikir sahibi olmanız açısından böyle bir yazı hazırlamaya karar verdim. REST kavramını anlamanız açısından yararlı olacağını düşünüyorum.

REST (REpresentational State Transfer)

REST client-server iletişimiyle ilgili bir mimari. HTTP protokol’ü ile paralel olarak gelişmiş olmasının yani sıra bugün en çok hepimizin aşina olduğu World Wide Web sisteminde kullanılıyor. REST mimarisini kullanan servislere genel olarak RESTful servis deniyor. Ana fikir aslında client-server arasında ki veri alışverişini SOAP, RPC gibi kompleks mimarilerle sağlamak yerine, HTTP protokolü üzerinden sağlamak. Çünkü zaten World Wide Web dediğimiz yapı HTTP protokolü üzerine kurulu. RESTful servisler SOAP, RPC’nin aksine basit ve hafiftirler.

Basit olmalarının yanında oldukça da esnek ve yeteneklidirler. Aslında tipik Web Servislerle yapabileceğiniz herşeyi RESTful servislerle yapabilirsiniz. Ayrıca mimari olarak nasıl olması, ne gibi özelliklere sahip olması hakkında belli yönergeler olsa da, burada SOAP gibi keskin standartları olan bir mimariden bahsetmiyoruz. Üzerine çoğu platformda (C#,JAVA vs.), bir sürü Framework yazılılmış durumda, fakat birçok platformun standart library’leri kullanılarak, kendimiz de hızlıca REstful Servisler geliştirebiliriz. REST Mimarisi ve LEGO arasında bir takım benzerlikler var aslında, birazdan açıklayacağım 🙂

SOAP ile en büyük farkı, SOAP gibi bizi proxy kullanmaya, bir WSDL’e zorlamıyor olması (tamam teorik olarak sizde WSDL importer’ları proxy generator’ları kullanmak zorunda değilsiniz, kendiniz de yapabilirsiniz). Bunun avantajları ve dezavantajları var tabiki.

REST mimarisindeki önemli noktalardan biride her HTTP request’inde yapılması istenilen işlemin HTTP Method’larıyla (Verb) ifade edilmesi. POST, PUT, DELETE ,GET gibi. Böylece proxy ihtiyacı ortadan kalkmış oluyor ve platform bağımsız yapılar kurmak kolaylaşıyor. Şuanki modern uygulamalarda bu Method’ları harfiyen kullanmak bir zorunluluk olmasa da, standartlara uymak, işlem tutartlılığı ve güvenliği açısından önemli. Bu Method’ların üzerinden yazının ilerleyen bölümlerinde geçeceğim.

RESTful servisler’in birçok farklı response tipi olabilir. Bugünlerde popüler olarak JSON kullanılıyor fakat XML, CSV veya amaca bağlı olarak HMTL bile kullanılabilir. İlginç olan, önceki yıllarda bandwith düşük olmasına rağmen SOAP tabanlı servisler kullanarak kocaman kocaman verileri XML gibi verinin boyutunu daha da şişiren yöntemlerle aktarıyorduk. Şuan bandwith inanılmaz boyutlara ulaşmış durumda ve biz veri transferinde verinin boyutunu XML’e göre inanılmaz küçülten JSON kullanıyoruz, hem de JSON yıllardan beri varolmasına rağmen. Neyse 🙂

SOAP’ın aksine RESTful servislerin response’ları insan tarafından daha rahat anlaşılabilirler.

Bugün birçok şirket RESTful servisleri kullanıyor ;

  • Twitter’ın, Facebook’un Rest API’si var.
  • Google’un, Amazon’un, Azure’un çeşitle amaçlarla kullanılabilecek bir sürü REST servisi var.
  • Dünyanın en ünlü oyun firmalarından Blizzard Word of Warcraf oyuncularına karakterleri ile ilgili bilgileri RESTful servisler aracılığıyla sunuyor. Hatta yakında Diablo 3’de benzer bir API gelicek.
  • Eve Online’ın da benzer bir REST API’si var.

Rest servisler ;

  • Platform bağımsızlar. (Client’ın Windows, Server’ın Linux olmasının hiç bir önemi yok)
  • Dil bağımsızlar .
  • HTTP üzerinden çalışıyorlar.
  • Esnekler ve çok kolay genişletilebilirler.

Ayrıca belli kısıtları da var ;

Bunlara kısıttan daha çok REST mimarisinin hangi sınırlar içerisinde yer almasını belirleyen prensipler diyebiliriz.

Kısıtlar

Clint-Server Mimarisi : Burada anlatılmak istenilen aslında Separation of Concerns prensibi. Client’ın Server tarafındaki veri kaynağı hakkında hiç birşey bilmemesi, Server’ın da doğru istekler geldiği sürece doğru yanıtı vermesi. Client ile Server’ın birbirlerinden bağımsız olması. Amaç aslında platform bağımsız çalışmayı ve scalability’i arttırmak. Ayrıca aralarında ki interface ortak kaldığı sürece birbirlerinden bağımsız bir şekilde gelişmeleri de sağlanmış oluyor.

Stateless : Server tarafında client ile ilgili bir context veya Session tutulmaz. Client tarafından yapılan her request Server’ın response verebilmesi için gerekli bilgiyi taşır, yani her türlü state client tarafında tutulur, ihtiyaç duyulursa request içerisinde server’a bildirilir. Bu Scalability açısından da önemlidir, çünkü server’ın requestler arasında herhangi bir state’i saklamasını gereksiz kılar ve kaynak yönetimini kolaylaştırır. Visibility açısından önemlidir, çünkü request’in amacını anlamak için tek bir request’in içerdiği bilgiler yeterlidir.

Tabi stateless olmasının bazı dezavantajlarıda var. Client her request’de gerekli bilgileri eklemek zorundadır bu da network trafiğini arttırır. Bu ayrıca server’ın uygulamanın davranışlarındaki tutarlığı kontrol etmesini zorlaştırır, çünkü birçok farklı client’dan farklı içerikli requestler gelebilir, server’a validasyon açısından daha fazla yük binebilir.

Cacheable : HTTP response’ları client tarafından “cache”lenebilir, o yüzden Server gönderdiği response’ların cacheable olup olmadığını belirtmek durumundadır, bu performans açısından önemlidir.

Uniform Interface : Client-Server’lar arasında ortak, tekbiçimli arayüzlerin olması REST’in en önemli prensiplerinden biridir. Bu hem iletişim yöntemini basitleştiriyor hem de ortak bir interface olması sayesinde her parçanın birbirinden bağımsız bir şekilde evrimleşmesine olanak sağlıyor. Bu konu daha önce bahsettiğim HTTP Methodları ilede alakalı.

Bununla ilgili çok güzel bir örnek var, yukarıda LEGO’dan bahsetmiştim. LEGO ile oynayanlar bilirler, birbirinden farklı LEGO parçaları olsa da, onları birleştirmenin sadece birkaç yolu vardır, herhangi bir alışveriş mağzasından aldığınız yeni LEGO parçası, elinizdeki parçalarla kolay bir şekilde entegre olur, çünkü zaten standartları önceden tanımlanmıştır. Aklınıza “LEGO parçalarının birbirlerine bağlamanın bu kadar az yolu varken ortaya büyük şeyler çıkabilir mi?” gibisinden bir soru gelebilir. Sorunuzun cevabını buradan alabilirsiniz 🙂

Layered System : Burada kast edilen aslında client’ın son server’a mı yoksa bir aracı server’a mı bağlandığını bilmiyor olması, yani her katman aslında tek bir katmanı biliyor. Bu tür bir yapıya olanak sağlamasıyla birlekte, aracı serverlar load-balancing yaparak scalability arttırabiliyor ve client’ları belli security policy’lerine zorlayabiliyorlar. Bu yapı ayrıca encapsulation yapılması gereken yerlerde kullanılabiliyorlar.

Tabi böyle bir pipe-line’ın aşırı kullanımı client — server arasında gecikmelere sebep olabiliyor.

Code on Demand : Server belli durumlar’da client tarafındaki fonksiyonaliteyi arttırmak veya değiştirmek için, client tarafına executable scriptler gönderebilir. Böyle bir kullanım bazı durumlarda Visibility’i düşürdüğü için, Code on Demand tek opsiyonel kısıttır.

Eğer bir servis Code on demand kısıtı hariç diğer kısıtları içermiyorsa tam olarak RESTful servis değildir. Bu kısıtların çoğu, bugünün modern programlama ortramlarında endişe edilmesi veya uygulanması zor kısıtlar değiller. Ayrıca bu kısıtların çoğu bize yabancı gelen kavramlar değiller, çoğumuz kendi mimarilerimizde de kullanmışızdır. Bence zaten en dikkat edilmesi gereken kısıt REST’in Stateless olması. REST’in hedefledikleri aslında ; Scalability, Simplicity, Modifiability, Visibility, Portability ve Reliability. Yukarıdaki kısıtlara ne kadar uyarsanız, hedeflediklerini o kadar gerçekleştirmiş olursunuz.

Resource ve URI

REST mimarisinin kalbinde Resouce kavramı yatmaktadır. Resource kavramı REST’e özel bir kavram değil, halihazırda Web Browser’larda kullanmaktayız. Resource’lar herşey olabilir, entity, item veya dışarıya açmak istediğiniz herhangi birşey. REST resource’larını URI üzerinden tanımlar, SOAP’daki gibi “GetProductName”, “GetProductPrice” gibi method’lar veya servisler üzerinden iletişim kurulmaz. Mesela ;

/products/productname/25

/users/username/45

ve ya

/users/GetUser

/users/DeleteUser

gibi daha tanıdık gelen resource’larda oluşturabilirsiniz.

Aslında URI templateleri oluşturuyorsunuz ;

weatherForecast/{state}/{city}

weatherForecast/{state}/{city}?date={date}

gibi. Hatta isterseniz ;

/products/productname/25?dataFormat=json gibi şeyler yaparak verinin geri dönüş tipini de belirtebilirsiniz. Buna da Resource Representation deniyor, bir response’un nasıl bir veri tipiyle döndüğü tamamen sizin tasarımınıza kalmış, isterseniz bir çok farklı tipi de destekleyebilirsiniz ya da sadece tek bir tip desteklersiniz. Yukarıda HTTP Method’larından bahsetmiştim. Mesela /users/GetUser’a request’de bulunurken GET Method’u ile gitmek veya /users/DeleteUser DELETE Method’u ile gitmek sağlıklı olur. Dediğim gibi bununla ilgili daha detaylı açıklama yapacağım.

Resource kavramı REST’in kalbi, o yüzden RESTful bir servis yazmadan önce mutlaka Resource’larınızı tasarlayın.

HTTP Method’ları ve REST’de Kullanımı

REST’deki en önemli konulardan biride HTTP Method’ların nasıl kullanılması gerektiği mevzuu.

Öncelikle Idempotent kavramından bahsedilim. Matematik ve bilgisayar biliminde bir fonksiyonun bir defa uygulanması ile birden fazla defa uygulanması, sonucu değiştirmiyor ise bu fonksiyon Idempotent’dir. HTTP methodları arasında GET, PUT, DELETE Idempotent methodlardır. POST değildir.

Bugün aslında GET ve POST her işimizi görüyor. Peki neden POST yerine PUT ve ya silmek için ayriyetten DELETE method’larına da kullanmamız gerekiyor. Bunun birkaç sebebi olmasına rağmen bu sebeplerin hiç biri bizi PUT ve DELETE kullanmak zorunda bırakan sebepler değil. Ama REST’in tek amacı data’ya en basit şekilde ulaşmak değildir, REST aynı zamanda data’ya anlamlı bir şekilde ulaşma metadolojisidir, bir request’e baktığınız zaman onun ne iş yaptığını anlamanız önemlidir. Ayrıca idempotency kavramı da bu noktada önemli. Akla ilk gelicek sorulardan biri POST mu? PUT mu?

PUT ve POST arasındaki kavramsal farktan daha öncede bahsettik, PUT idempotent bir method, yani aynı Resource’a yaptığınız aynı PUT request’ini bir veya birden fazla defa yapmanız sonucu değiştirmez. Fakat POST aynı şey değil, o yüzden browserlar bizi POST yapılan bir yerde refresh, back gibi şeyler yaptığımızda uyarır, çünkü server’da ilgili resource’un state’i değişebilir. Tamam uygulamayı biz yazıyoruz, requestleri karşılayan bizleriz, POST’un da aynı davranışını sergilmesini sağlayabiliriz fakat client açısından mesela browserlar açısından PUT ve POST arasında çok fark var. Uniform Interface kısıtında da aslında kast edilen bu.

Demek istediğim create işlemlerinde PUT kullanın değil, kafanız karışmasın, tam anlamıyla gerektiği yerde kullanmak lazım. Mesela ;

HTTP/1.1 PUT /DataStorage/Pictures/deniz.jpg
...<deniz.jpg'in içeriği ... >

Şeklinde bir request ile deniz.jpg adında bir resource’u server’da yaratıyoruz, bu request’i 100 kere de göndersek fark etmez çünkü hep deniz.jpg’yi gönderiyoruz. Bütün content’i aynı spesifik bir Resource’a gönderiyoruz. Fakat ;

HTTP/1.1 POST /DataStorage/Pictures

<?xml version="1.0" encoding="UTF-8"?> 
<DataStorage operation="add" type="jpeg">
<[CDATA[ <herhangi bir resmin içeriği > ]]>
</DataStorage>

Farklı anladınız mı? Eğer bu request’i birden fazla tekrarlarsak, aynı content’e sahip 2 adet resim server tarafında oluşur. POST’un gücü ve tehlikesi de bu, POST ile herşeyi yapabilirsiniz, Create,Delete,Update herşeyi.

Mesela tekrar bir örnek verelim. Bir forum siteniz var ve bir başlığın altına yorum eklemek istiyoruz, ilgili alanları doldurduktan sonra POST ederiz, çünkü bu aşamada bize PUT’daki gibi HTTP 200 (No error, operation successful.) response’u yetmez, çünkü aynı zamanda bir resource’da değişiklik yapıyoruz ve yaptığımız değişikliği görmek isteriz, o yüzden ASP.NET’de Postback kavramı vardır.

Aslında özetle şunu demek istiyorum ;

  • Create = Eğer spesifik bir Resource’un bütün bir içeriğini gönderiyorsanız PUT kullanın.
  • Create = Eğer server’a spesifik bir Resource’a bağlı olan içerik gönderiyorsanız POST kullanın.
  • Retrieve = GET.
  • Update = Eğer spesifik bir Resource’un bütün bir içeriğini gönderiyorsanız PUT kullanın.
  • Update = Eğer spesifik bir Resource’a bağlı bir veya birden fazla içerik değiştiriyorsanız POST kullanın.
  • DELETE = 🙂

Ayrıca bu method’ların response kod’larıda client açısından büyük önem taşır, bu kodları incelerseniz, nerede hangi Method’u kullanmanız gerektiği kafanız daha iyi oturur.

REST konusunu araştırırken en çok takıldığım konulardan biri de nerede POST nerede PUT konusuydu. O yüzden bu kısmın üzerinde bu kadar çok durdum.

REST Mimarisinde Security

REST, SAOP veya RPC’de ki gibi hazır bir security yapısıyla gelmiyor, aslında bir security yapısıda dayatmıyor. Yine de kullanabileceğiniz bir çok yöntem söz konusu.

REST’in HTTP protokolünü kullandığından bahsetmiştik, HTTP’nin de kendine has Authentication mekanizmaları var, bunları kullanmamız açısından hiç bir engel yok. Mesela bunlardan en popüleri Basic Access Authentication. Kullanması çok kolay, fakat kesinlikle HTTPS ile beraber kullanılması gerekiyor, çünkü şifreyi plain-text olarak gönderiyor, HTTPS ile kullandığımız zaman encrypted olarak gönderebiliyoruz.

Diğer alternatifimiz ise Digest Authentication, bu da HTTP’nin Authentication mekanizmalarından birisi. Bu mimaride şifre plain-text olarak gönderilmek yerine, data’nın o şifre ile hash’i alınır öyle gönderilir. Server gelen datanın hash’ini aynı şifre tekrar alır ve hashleri karşılaştırır böylece datanın valid bir yerden gelip gelmedğini anlar. Tabi buradaki en önemli nokta client ile server’ın şifreyi bilmesi gerekliliği ki server’da aynı şifre ile hash alıp karşılaştırma yapabilsin.

Olaylar şu şekilde gelişiyor, client server’a bir request’de bulunuyor ve server 401 (“Unauthorized”) response’unu döndürür. Client bu cevabı aldıktan sonra bunun Authorization gerektiren bir request olduğunu anlar ve request’in Header’ına Authorization datasını gömer (Hash’li data), server bu sefer istenilen yanıtı verir. Basic Access Authentication’dan daha güvenli bir yöntem olsa da hala brute force gibi saldırılara açıktır ayrıca bütün server ve browser’lar tarafından desteklenmemektedir.

Tabi tek seçeneğimiz HTTP’nin bize sağladığı güvenlik mekanizmaları değil hata günümüzde çoğunlukla RESTful servislerde HMAC (Hash Message Authentication Code) yöntemini kullanılıyor. Aslında bu costum bir yapı, digest’deki gibi “Authorization” header üzerinden security bilgilerini yolluyoruz. Olay şu ;

Server client’a bir şekilde userId ve secret key sağlıyor. Nasıl sağladığının hiç bir önemi yok, bu konuyu araştırken en çok bu noktaya takılmıştım, siz takılmayın. Yani adam bir şekilde bir yere user id ile kayıt olur oradan alır veya email ile kendisine gelir veya normal postayla :). Önemli olan Server’ın Client’a bu bilgiyi sağlamış olması ve kendi tarafında user ile ilişkili olarak bu key’i tutuyor olması.

Client bu aşamadan sonra bütün requestlerini bu userid ve key ile imzalayıp öyle gönderirir. Burada dikkat edilmesi gereken nokta Server’ın Client’a request’in hangi kısımınlarını, hangi algoritma ile imzalayacağını bildirmesi gerekliliği. Çünkü client her request’de kendisine verilen algoritmayla HMAC Hash’ini üretip, userid’si ile beraber “Authorization” header’ına gömmeli.

Authorization: dirgin:uBMfGaLjue+TSDygYB5aEg==

Server request’i aldıktan sonra “Authorization” header’ı alıp split eder ve gelen userid’nin kendi tarafında kayıtlı olan key’ini bulur, ardından request’deki ilgili alanların HMAC Hash’ini bu key ile tekrar alır ve kendisine gelen Hash ile karşılaştırır. Eğer hash’ler aynıysa kullanıcının yetkili bir kullanıcı olduğu anlaşılıp doğru response dönülür.

HMAC yaklaşımı Basic Access Authentication ve Digest Authentication’a göre daha etkili bir yaklaşım verilen key random ve yeterince uzunsa brute force saldırılarına karşıda etkili. Ayrıca paranoyak olmanızı gerektiren bir durum varsa kullanıclara verilen keylerin belli bir süre sonra expire olmasını sağlayabilirsiniz böylece kullanıcı belli aralıklarla yeniden bir key edinmek durumunda kalır. Bu yaklaşım RESTful servislerde en çok kullanılan yaklaşım.

REST vs SOAP

Bu kadar REST anlattıktan sonra insanın aklına SOAP mı? REST mi? sorusu geliyor elbette 🙂

Bana sorarsanız bir Web Servis tasarlarken önce REST’i deneyin, (yapamadığınız şeyler olursa ki bu durumlar çok az) SOAP’ı deneyin. Bu aşamada karşılaştırmalı gitmekte yarar var.

REST’in avantajları nelerdir ;

  • Hafiftir, kolay extend edilebilir.
  • Gelen, giden data boyutu SOAP ile karlılaştırıldığında çok ufaktır
  • Tasarlaması kolaydır ve implementasyonu kolaydır, herhangi bir ekstra tool’a ihtiyacı yoktur
  • HTTP üzerinden çalışır, platform bağımsızdır

SOAP’ın avantajları ;

  • Consume etmesi kolaydır, bir şemayla beraber gelir
  • Type-safety’dir, sizi bu tür validasyonlarla uğraştırmaz
  • Bir sürü development tool’u vardır
  • Security implementasyonu REST’e göre daha kolaydır, bir sürü hazır yapı vardır.

En genel manada ikisinin de avantajları bunlar. Benim görüşüm enterprise uygulamalarda SOAP daha kolay bir çözüm olabiliyor. Onun haricinde dediğim gibi SOAP ile yapıpta REST ile yapamayacağınız hiç birşey yok. O yüzden önce REST’i deneyin her zaman.

Evet böylece bir yazımızın daha sonuna gelmiş olduk, umarım REST kavramı kafanızda oturmuştur. Soru, görüşlerinizi her zaman bildirebilirsiniz.

Exit mobile version