REST, Idempotency ve HATEOAS Kavramları

Duygu Demirbaş
Kodcular
Published in
7 min readSep 7, 2022

REST genellikle HTTP protokolunu kullanan bir mimari stildir.

REST( Representational State Transfer);

  • client–server arasında kolay ve hızlı bir şekilde iletişim kurulmasını sağlayan mimari stildir.
  • proxy kullanmaya (wsdl) ihtiyaç duymaz.
  • state bilgisi tutulmaz.
  • platform ve dil bağımsızdırlar.
  • Response tipi olarak genellikle daha hafif ve insan tarafından okuması kolay olan JSON tercih ediliyor fakat amaca göre XML, HTML de olabiliyor.
  • Soap’a göre gelen giden data boyutu oldukça küçüktür.

Rest mimarisini kullanan servislere RESTFul servisler diyoruz.

REST API Kısıtları

REST, herhangi bir web hizmetini gerçek bir Restful API yapan 6 mimari kısıtlamayı şöyle tanımlar:

1- Uniform Interface

Client ve Server arasındaki arayüzü tanımlar. Her parçanın bağımsız olarak gelişmesini sağlayan mimariyi basitleştirir ve ayrıştırır.

2- Client Server

Sepereation of Concerns ilkesine göre client ve serverın bağımsız olarak geliştirilmesini sağlayan patterndir. Client serverın sorumluluğunda olan depolama işlemleri gibi konularla ilgilenmezken, server’da clientın sorumluluğunda olan state gibi konularla ilgilenmez ve birbirinden bağımsız olarak geliştirilebilir.

3- Stateless

Client’dan Server’a yapılan her requestin talebi anlamak ve tamamlamak için gerekli tüm bilgileri içermesini zorunlu kılar. Server client hakkında herhangi bir session bilgisi ya da kaç kere istek yapıldığı gibi bilgileri tutmaz.

4-Cacheable

Server gönderdiği responseların cachelenebilir ya da cachelenemez olduğu bilgisini de client’a döner, bu sayede client bunun üzerine bir kurgu tasarlayabilir.

5-Layered System

Mimarinin katmanlı hiyerarşik katmanlardan oluşmasına izin verir ve her bileşen etkileşimde bulundukları yakın katmanı tanır, ötesini göremez.

6-Code on Demand (optional)

Zorunlu olmayan tek kısıt server’ın client’a belirli durumlarda executable scriptler gönderebilmesini sağlar.

Eğer bir servis Code On Demand kısıtı hariç kısıtları sağlamıyorsa tam olarak RESTFul servis değildir.

HTTP Statu Kodları :

Http Statu kodlarının anlamları genel olarak şu şekildedir.

  1. 1xx — Bilgilendirme
  2. 2xx — Başarılı İşlem
  3. 3xx — Yönlendirme
  4. 4xx — Kullanıcı Kaynaklı Hata
  5. 5xx — Server Kaynaklı Hata

HTTP Methodlar

En çok kullanılan HTTP methodlar şu şekildedir.

GET : Sorgulama yapmak için kullanılır.

POST : Yeni bir kayıt oluşturmak için kullanılır.

PUT : Var olan entity’deki tüm alanlarda güncelleme yapmak için kullanılır.

PATCH : Var olan entity’deki belirli alanlarda güncelleme yapmak için kullanılır.

DELETE : Var olan kaydı silmek için kullanılır.

REST API Tasarımı:

Rest API tasarımının en önemli kısmı isimlendirmedir. Rest Api tasarlarken resource(kaynak) yani URL, filler ve statu kodları gibi kavramlar vardır. HTTP Methodlar api isimlendirmede oldukça önemli bir role sahiptir. Yazılım geliştirirken isimlendirmemizi genellikle şu şekilde yaparız :

bir sipariş vermek için => orderProduct()

iptal etmek için => cancelOrder()

güncellemek için => updateOrder()

Fakat REST Api tasarlarken bu isimlendirmedeki filleri kaldırır, HTTP Methodlar ile yapılacak işi tanımlar, isimler üzerinden ilerleriz. İsimleri de çoğul olarak tanımlarız. PathVariable kullanarak bir kaynaktaki bir nesneye ulaşırız. Aşağıdaki örnekte order resource’u ile ilgili bir kaç kullanımı inceleyelim.

  • bir sipariş vermek için => POST ‘/orders/’
  • iptal etmek için => DELETE ‘/orders/{orderId}’
  • güncellemek için=> PUT or PATCH ‘/orders/{orderId}’
  • sorgulama yapmak için => GET ‘/orders/{orderId}’

Hiyerarşik ilişkileri belirtmek için slash(/) kullanırız.

  • GET ‘/orders/{orderId}/invoice’

Versiyonlama aşağıdaki şekillerde yapılabilir :

  • GET ‘/orders/v2’
  • GET ‘/v2/orders’

HTTP Verb’ler kaynakta yapılacak işlemin tipini belirtmek için kullanılır.

NE ZAMAN PUT NE ZAMAN PATCH KULLANMALI ?

İki method da kayıt güncellemek için kullanılır fakat aralarında şöyle bir fark vardır.

PUT /books/1
{
"name": "book1",
"author": "author2" // new author
}

PUT isteğinde bir entity’nin tüm alanları replace edilirken, PATCH isteğinde ise sadece gönderilen alan güncellenir.

PATCH /books/1
{
"author": "author2" // new author
}

HTTP Methodlarında Safe ve Idempotent Kavramları

Safe, client tarafından yapılan request’in server üzerinde herhangi bir değişiklik yapmadığı (read-only) işlemlerdir.

Idempotent ise, bir methodun ya da fonksiyonun bir ya da birden çok defa çağrılması sonucu değiştirmiyor ise bu method ya da fonksiyon idempotent olarak nitelendirilir.

+---------+------+------------+
| Method | Safe | Idempotent |
+---------+------+------------+
| CONNECT | no | no |
| DELETE | no | yes |
| GET | yes | yes |
| HEAD | yes | yes |
| OPTIONS | yes | yes |
| POST | no | no |
| PUT | no | yes |
| TRACE | yes | yes |
+---------+------+------------+

Aşağıdaki örnekte getId() methodundan dönen değer her zaman 1'dir, yani idempotent bir fonksiyondur.

public Integer getId() {
return 1;
}

Fakat setId() methodunda dönen değer inputtaki parametreye göre değişecektir ve idempotent değildir.

public Integer setId(Integer id) {
return id++;
}

HTTP Methodlar açısından da şu şekilde bir örnek verebiliriz.

GET/books/1

ID’si 1 olan kitabı getirir, birden çok kere de çağrılsa aynı sonucu döner idempotent’tir.

PUT /books/1 Body: {'name':'Clean Code','author':'Robert C. Martin'}

ID’si 1 olan kitabın bilgilerini Body’de gönderilen bilgiler ile günceller. Birden çok kere çağrılsa da 1 ID’li kitap ile ilgili aynı değişikliği yapar, idempotent’tir.

POST/books Body: {'name':'Refactoring','author':'Martin Fowler'}

ID’si 2 olan yeni bir kayıt yaratır. Aynı isteği bir daha gönderirsek ID’si 3 olan yeni bir kayıt daha yaratır, yani idempotent değildir.

REST mimarisinde bir Request’e baktığımızda onun ne iş yaptığını anlamamız önemlidir. HTTP spesifikasyonlarında karşımıza çıkmasına rağmen bazen sadece GET ve POST kullanarak update/delete gibi işlemlerin de yapıldığına denk gelmiş olabilirsiniz, fakat bu methodların hepsini spesifikasyonlara uygun şekilde kullanmak işlem güvenliği ve tutarlılığı açısından önemlidir.

Örneğin GET methodu ile veritabanına insert işlemi gerçekleştirirsek, client’ımız GET requestinin safe olduğunu varsaydığı için requestini birden çok tekrarlayabilir, bu da istenmedik bir şekilde veritabanında mükerrer kayıtlara yol açabilir.

Yukarıdaki tabloda da gördüğümüz üzere PUT idempotent iken POST idempotent değildir. Bir örnek ile detaylandıracak olursak, bir ödeme emri üzerinde güncelleme yapmak istediğimizi var sayalım, PUT methodu ile bir istek yaptığınızda, o ödeme emri ile ilgili güncellemeyi yaparsınız, client birden çok kere de çağırsa aynı güncelleme işlemini yapacaktır, fakat bu request’i POST ile gönderdiğinizde idempotent olmadığı için bunu ikinci bir ödeme emri olarak kabul eder ve kaynak sunucuda mükerrer bir ödeme emri daha oluşturur.

POST Method’u ile Idempotency Nasıl Sağlanabilir ?

HTTP Method’lar neden default olarak idempotent değil gibi bir soru gelmiş olabilir aklınıza. Eğer POST default olarak idempotent olsaydı aynı değeri dönebilmesi için gönderilen isteğin zaten bir biçimde sunucu üzerinde mevcut olması gerekirdi ki her zaman aynı sonucu dönsün. POST methodunun idempotent olmama sebebi budur.

Peki POST methodunun idempotent olmasına ihtiyacımız varsa, örneğin bir ödeme emri requestinin client tarafından sunucuya iletildiğini fakat networksel bir sorundan dolayı client’ın cevabı alamadığını ve cevap alamadığı için de aynı requesti tekrar gönderdiğini varsayalım. Bu durumda sunucu tarafında aslında ödeme emri gerçekleştiği için ikinci bir ödeme emrinin oluşturulmasına sebep olur.

POST methodunu idempotent yapmak için biraz araştırma yaptığımda şöyle bir çözümün uygulanabilir olduğunu gördüm; Request Header’da Idempotency-Key alanında unique bir key gönderilerek, sunucu tarafında işlem yapılmadan önce bu key ile veritabanında bir kayıt var mı kontrol edilebilir, böylece bu key ile bir kayıt varsa o ödeme emrine ait bilgiler dönülür, yok ise de yenisi oluşturulabilir. Böylece POST methodunun idempotent olması sağlanabilir.

Eğer her seferinde veritabanına gidip bu kontrol yapılmak istenmiyorsa in-memory cache ile gönderilen unique id yine kontrol edilir, aynı unique id ile istek gelmiş ise cache’den bu bilgi getirilerek client’a cevap dönülebilir.

Richardson Maturity Model

Leonard Richardson REST mimariyi hangi seviyelerde kullandığımızı anlamak için bir REST olgunluk modeli geliştirmiş.

Bu modele göre olgunluk seviyeleri 3 seviyeden oluşuyor.

Level-0 REST mimariyi en alt seviyede, Level-3 ise en üst seviyede kullandığımız anlamına geliyor.

Level-0 => REST’i bir taşıma protocol’ü olarak kullanmaktan bahsediyor. Tek bir URI ve HTTP Method (POST) kullanan servislerdir.

Level-1 => Her resource için ayrı bir URI kullanan ancak tek bir method (genellikle POST) kullanan servislerdir.

Örnek: http://ornek-api.com/books/1 dediğimizde book resource’u altındaki 1 ID’li nesneye erişmek istediğimi URI üzerinden belirtmiş olurum.

Level-2 => Her resource için ayrı bir URI kullandığı gibi, her bir işlem için de standartlara uygun HTTP Methodlarının (GET,POST,PUT, DELETE) kullanıldığı servislerdir. Bu servisler iyi bir olgunluk seviyesine erişmiş demektir.

Level-3 =>Olgunluk seviyesi en yüksek olan servislerdir. Level-2 ye ek olarak herhangi bir URI çağırıldığında responseda bu URI ile yapılabilecek tüm işlemlerin URI ile istemciye döndürülmesini de içerdiği anlamına gelir. Bu yönteme HATEOAS ismi verilmektedir.

HATEOAS KAVRAMI

Bir Rest Call yaptığımızda normal olarak istediğimiz kaynak ile ilgili bilgiler görmeyi bekleriz. Fakat iyi tasarlanmış bir REST API bize istediğimiz kaynak ile ilgili bilgiyi dönmekle birlikte, bu kaynak ile ilgili diğer kaynakların, yapılabilecek işlemlerin listesini de response’da gönderir.

Paypal’in developer sitesini incelediğimizde HATEOAS linklerini aşağıdaki gibi paylaştığını görüyoruz.

GET isteği yaparak ilgili ID’ye ait payment işlemini listeleyebileceğimizi, iade (refund) işlemi yapmak istiyorsak POST isteği ile yapabileceğimizi ya da parent payment’ı görmek için GET isteği yapabileceğimizi görüyoruz.

HATEOAS kavramı tek bir endpointten bir istek yaptıktan sonra, uygulamada neler yapabileceğimizi görmemize, API’lerin yeteneklerini keşfetmemize olanak sağlar.

Rest ile ilgili öğrendiğim, araştırdığım konuları bir araya toparladığım bu yazıyı beğendiyseniz alkışlayarak ya da paylaşarak destek olabilirsiniz.

Kaynak :

Richardson Maturity Model (martinfowler.com)

REST Architectural Constraints (restfulapi.net)

What is REST — REST API Tutorial (restfulapi.net)

HATEOAS — Wikipedia

--

--