REST API

Hamza Coşkun
SDTR
Published in
9 min readMay 16, 2023

REST API nedir?

REST API, bir API mimarisidir. Diğer mimariler gibi REST’in de belirli stilleri vardır ve bu stillere uymak çalışmalarımızı spesifik kalıplara sokar. REST, sunucu ve istemcinin birbiriyle olan iletişimini standartlaştırır. Böylelikle sunucunuzun arka planını bilmeyen birisi rahatlıkla sizin sisteminizi kullanabilir veya siz başkasının sistemini kullanabilirsiniz.

REST, iletişim için HTTP protokolünü kullanır. İşlemleri de HTTP metotlarıyla yapar (GET, POST, PUT, DELETE vb.)

Bir blog sitesi hazırladınız diyelim. Başka bir geliştirici, kendi uygulamasından sizin sitenize blog yazdırmak istiyor. İşte bunun için sizin REST API’ınıza POST request atması gerekir. Böylelike siz bu request’i işleyerek bloğu kendi sisteminize kaydedersiniz.

REST API’ın özellikleri

Uniform Interface

İstemci ve sunucu arasında bir arayüz görevi görür. İstemcinin ve sunucunun yapısından bağımsızdır. Hangi veritabanını veya hangi dili kullandığınız REST API’nin umrunda bile değildir.

Stateless

Sunucu, istemcileri tanımaz ve durum bilgisi tutmaz. Örneğin A istemcisinin POST, GET, DELETE requestlerini atmasıyla. Her bir request’i farklı bir istemcinin atması arasında backend tarafında hiçbir fark yoktur. Bu nedenle istemci her request attığında, o request’in işlenmesi için tüm detayları vermek zorundadır.

Bu durum sayesinde REST API ölçeklenebilir hale gelir. Sunucu hiçbir istemciyi tanımadığı için her request’i paralel olarak işleyebilir.

Layered System

İstemciye göre sunucu bir kapalı kutudur. İçeride olan bitenle ilgilenmez dolayısıyla sunucu MVC gibi yapılar kullanabilir. Çeşitli katmanlara bölünebilir.

Cacheability

Sunucu gönderilen bilginin cache’te tutulup tutulamayacağının bilgisini istemciye verebilir. Bu sayede istemci daha az request gönderir.

Code on demand

Sunucu gönderilen request’e göre işlem yapar. Her response kendi request’ine özel olarak hazırlanır. Örneğin REST API ile bir arama işlemi yapacaksanız, sizin belirttiğiniz şartlar doğrultusunda arama yapılır.

Request’lerin yapısı

Header – Request’in metadata’sını tutar.
Body – Request’in esas verisini tutar. Genellikle JSON formatındadır.
Operation – Request’in yapacağı işlemi tanımlar. Her Request HTTP metotlarından birine(GET, POST, PUT vb.) sahiptir.
Endpoint – Request’in adresini tanımlar. Örneğin: hamzacoskun.com/api/v1/blogs

Response’ların yapısı

Header – Request’te olduğu gibi, response’un metadata’sını tutar.
Body – Sunucudan gelen esas veridir. Çoğu zaman JSON formatındadır.
Status Line – Response’un durumunu tanımlar. HTTP Status Code adında 3 haneli önemli bir sayı tutar.

Örneğin Status Code, 200'ün bir küsüratıysa, bu işlemlerin başarıyla gerçekleştiği anlamına gelir. 400'ün küsüratıysa request hatalı demektir. 404 Not found hatası buradan gelir. Birazdan bu kodları daha detaylı inceleyeceğiz.

Request & Response Örneği

Sitemizdeki blogları okumak için bir request gönderelim.

Request

Header — {‘Content-Type’: ‘application/json’}
Body – {}
Operation
– GET
Endpointhamzacoskun.com/api/v1/blogs/restful

Response

Header – {‘Content-Type’: ‘application/json’}
Body –
{“title”:”REST API”,”content”:”REST API sevgidir, birlik ve beraberliktir.”}
Status Line – 200 OK

HTTP kodları

100 Information — 1 ile başlayan HTTP kodları bilgilendirme içerir.

200 Success — 2 ile başlayan kodlar request’in başarıyla işlendiği anlamına gelir. Bu kodu alıyorsanız iki taraf da hayatından memnun diyebiliriz ancak sunucu size ekstra bilgi vermek isteyebilir.

Örneğin 201 Created kodu alırsanız, işleminiz başarılıdır ve sunucu tarafında yeni bir obje oluşturulmuştur veya 202 Accepted alırsanız sunucu size doğru şekilde cevap vermiştir ancak ortada gösterilecek bir içerik yoktur.

300 Redirection — 3 ile başlayan kodlar bağlandığınız endpoint’in artık geçersiz olduğu anlamına gelir. Çoğu zaman kullanılmaz çünkü doğrudan redirect edilirsiniz.

400 Client Error — 4 ile başlayan kodlar istemci tarafının günahkâr olduğu anlamına gelir. Yani sorun request’tedir. Örneğin olmayan bir bloğun endpoint’ine GET request atarsanız 404 Not Found cevabı alırsınız. Eğer yetkiniz olmayan bir request atarsanız 401 Unauthorized cevabı alırsınız.

500 Server Error — 5 ile başlayan kodlar sunucu tarafının günahkâr olduğu anlamını taşır. Gönderilen request doğru işlenemediğinde sunucu bu kodu döner.

Unutmayın ki sunucu tarafındaki geliştiricilerin gelen request’leri iyi şekilde validate etmesi çok önemlidir. Çünkü eğer request doğru şekilde validate edilmezse, bir Bad Request hatası döndürülmesi gerekirken sunucu hatalı da olsa o request’i işlemeye çalışacak ve içeride hata alacağı için 500 dönecektir. Ancak asıl sorun request’tedir. Bu tür hatalar production ortamında size baş ağrısı olarak dönebilir.

Tüm HTTP kodlarının listesine Wikipedia’dan ulaşabilirsiniz.

HTTP metotları

POST: Yeni bir veri oluşturur. Eğer zaten bir veri mevcutsa hata verebilir veya eski verinin üstüne yazabilir. Response olarak oluşan veriyi döner.
GET: Bir veriyi döner. Bu tür request’lerin body’si önemsizdir. Sunucu bu body’e bakmaz. İstemci de göndermez.
DELETE: Bir veriyi siler. Aynı GET request gibi body’si önemsizdir.

PUT: Bir veriyi günceller. Bu güncelleme işleminde tüm değerler belirtilir.
PATCH: Bir veriyi günceller. Bu güncelleme işleminde tüm değerlerin belirtilmesine gerek yoktur. Sadece belirtilen kısımlar güncellenir.

PUT metodunda tüm bilgileri girmelisiniz.

{
"title": "yeni başlık",
"content": "açıklama"
}

PATCH metodunda sadece belirttiğiniz bilgiler değişir.

{
"title": "yeni başlık",
}

OPTIONS: İstemci tarafındaki geliştirici, O endpoint’te hangi metotları kullanabileceğini görmek için bir OPTIONS request gönderir. Örnek bir response:

HTTP/1.1 200 OK
Allow: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization

TRACE: İstemcinin gönderdiği request’in tamamen aynısını 200 OK koduyla geri döner. Debugging için kullanılır.

CRUD fonksiyonlarının HTTP metotlarındaki karşılıkları

Create ➜ Post
Read ➜ Get
Update ➜ Put
Update ➜ Patch
Delete ➜ Delete

Safe ve/veya Idempotent metotlar

Safe: Bir metot ‘Safe’ ise, bu o metodun read-only olduğu anlamına gelir. Bu metot sunucu tarafında bir değişiklik yapmaz. Yazılımda kullandığımız Pure fonksiyonlardan farkı yoktur. Örneğin GET metodu safe metottur.

Idempotent: Bir metot ‘Idempotent’ ise, bu o metodun bir kez veya 30 kez gönderilmesinin arasında fark olmadığı anlamına gelir. Yani bu metotları üst üste atmanız sunucu tarafında ekstra değişikliğe neden olmaz.

Örneğin DELETE bir safe metot değildir çünkü sunucu tarafında değişiklik yapar fakat bir kere DELETE metodunu gönderdikten sonra kaç kez daha gönderdiğinizin önemi olmaksızın sunucu tarafında yeni bir şey meydana gelmez.

Her resource ayrı bir endpoint’e bağlı olmalıdır. Örneğin; blog, bir resource’tır ve bu nedenle bu resource ile ilgili CRUD işlemleri yapmak istiyorsam “hamzacoskun.com/api/v1/blogs” ve altındaki endpoint’lere request atmalıyım.

Tüm blogların listesini almak istiyorsam herhangi bir ID belirtmeden doğrudan “/blogs” endpoint’ine request atarak bir collections elde edebilmeliyim.

Tüm blogları okumak için:

GET hamzacoskun.com/api/v1/blogs

Yeni bir blog eklemek için:

POST hamzacoskun.com/api/v1/blogs

Response olarak, oluşan yeni bloğun ID’si dahil tüm bilgilerini dönmelisiniz.

3 ID’li bloğu okumak için:

GET hamzacoskun.com/api/v1/blogs/3

3 ID’li bloğu silmek için:

DELETE hamzacoskun.com/api/v1/blogs/3

3 ID’li bloğu güncellemek için:

PUT hamzacoskun.com/api/v1/blogs/3

Bloglarla ilgili bir REST API’niz varsa bu endpoint’lerin veya çok benzer alternatiflerinin işe yarıyor olması gerekir. Şimdi standartlara geçelim.

Standartlar

İsimlendirme

İsimlendirmelerde asla fiil kullanılmaz. Fiil’leri HTTP metotlar aracılığıyla belirtiriz. Bir blog oluşturmak için içinde ‘create’ geçen bir endpoint’e request atılmaz. Bloğun olduğu request’e GET request atarsanız okunur, DELETE request atarsanız silinir. Her biri aynı endpoint’e bağlıdır ama metotlar farklıdır.

✔ hamzacoskun.com/api/v1/blogs/restful
✘ hamzacoskun.com/api/v1/blogs/create/restful
✘ hamzacoskun.com/api/v1/createBlog/restful

X-Headers

X-Headers; standart olmayan, sunucu tarafından eklenen header’lar için kullanılan bir terimdir. Bu header’ların başında ‘X-’ ön eki vardır. Örneğin ‘X-Forwarded-For’.

Richardson Maturity Model

Leonard Richardson, 2008 yılında bir model önerdi. Bu model, REST API’nızın ne kadar olgun olduğunu, REST’i ne düzeyde kullandığınızı ölçmek için geliştirildi.

0. Düzey
Bu düzeyde yalnızca 1 URI ve 1 HTTP metodu kullanılır. REST’in sıradan bir taşıma protokolü olarak kullanıldığı düzeydir.

1. Düzey
Bu düzeyde resources’lar tanıtılır (blog, post, user vb.). Sisteminizdeki tüm resource’ların farklı URI’lara bağlandığı düzeydir.

2. Düzey
Bu düzeyde HTTP metotlarının kullanımına odaklanılır. Tüm metotların uygun şekilde kullanıldığı düzeydir. Bu düzeyden önce genellikle POST metoduyla iletişim sağlanırdı. Artık GET, POST, PATCH, PUT, DELETE gibi ihtiyaç duyulan tüm metotlar kullanılır.

3. Düzey
Bu düzeyde ek olarak HATEOAS prensibine uyulur. Bu prensibe birazdan değineceğiz ama özetlemek gerekirse HATEOAS, sunucunun response gönderirken içine ufak bir döküman da koyduğu bir prensiptir.

Richardson Maturity Model

HATEOAS (Hypermedia As The Engine Of Application State)

HATEOAS, geliştiricilen birbirlerleriyle daha iyi iletişim sağlaması için kullanılan bir prensiptir. Bu prensip gereği ben sizin API’ınızdaki bir endpoint’e request attığımda bana sadece gerekli bilgileri göndermezsiniz. Ekstra olarak o endpoint’le doğrudan ilgili, işime yarayabileceğini düşündüğünüz ve o an kullanabileceğim URI’leri de gönderirsiniz. Kısaca bu standart sayesinde dışarıdaki bir geliştirici sizin API’ınızı hızlıca keşfedebilir.

HAL (Hypertext Application Language)
HAL, REST API kaynaklarını ve bu kaynaklar arasındaki ilişkileri tanımlamak için geliştirilmiş bir standarttır.

İlk olarak, sunucu bir response gönderirken “_links” adında bir node’un içerisine ilgili endpoint’leri verir.

GET /books/1
{
"id": 1,
"title": "Harry Potter and the Sorcerer's Stone",
"author": "J.K. Rowling",
"publication_year": 1997,
"_links": {
"self": {
"href": "/books/1"
},
"collection": {
"href": "/books"
}
}
}

“_links” içindeki “self” bölümü o objenin kendisini temsil eder.

“collections” bölümü de objenin tüm özdeşlerinin bulunduğu diziyi temsil eder.

Örnek olarak, bu response’ta “author” belirtilmeseydi ve bunun için başka bir endpoint’e gidilmesi gerekseydi (/authors/17 gibi),

“_links”’in altında “author” adında başka bir node eklerdik (self ve collections gibi.) ve oraya endpoint’imizi belirtirdik. Böylece kitabın yazarına nereden erişilebileceği gösterilirdi.

İkinci olarak, Bir collections’a request attığınızda “_links”’e ek olarak “_embedded” adında bir node gelir.

GET /books
{
"_embedded": {
"books": [
{
"id": 1,
"title": "Harry Potter and the Sorcerer's Stone",
"author": "J.K. Rowling",
"publication_year": 1997,
"_links": {
"self": {
"href": "/books/1"
},
"collection": {
"href": "/books"
}
}
},
{
"id": 2,
"title": "To Kill a Mockingbird",
"author": "Harper Lee",
"publication_year": 1960,
"_links": {
"self": {
"href": "/books/2"
},
"collection": {
"href": "/books"
}
}
},
{
"id": 3,
"title": "1984",
"author": "George Orwell",
"publication_year": 1949,
"_links": {
"self": {
"href": "/books/3"
},
"collection": {
"href": "/books"
}
}
}
]
},
"_links": {
"self": {
"href": "/books"
}
}
}

“_embedded” bölümünde o collections’ın içerdiği tüm objeleri bulabilirsiniz. Bu, tüm objelere ihtiyacınız olduğunda kullanmanız gereken bir endpoint’tir. Örneğin uygulamanız açılırken tüm kitapları cache’e alacaksanız doğru bir kullanımdır.

Bir de PayPal’ın API’ına göz atalım bakalım onlar nasıl yapmış:

{
"links": [
{
"href": "https://api-m.paypal.com/v1/payments/sale/36C38912MN9658832",
"rel": "self",
"method": "GET"
},
{
"href": "https://api-m.paypal.com/v1/payments/sale/36C38912MN9658832/refund",
"rel": "refund",
"method": "POST"
},
{
"href": "https://api-m.paypal.com/v1/payments/payment/PAY-5YK922393D847794YKER7MUI",
"rel": "parent_payment",
"method": "GET"
}
]
}

Gördüğünüz üzere tüm linklerin mevcut objeyle olan ilişkisi “rel” altında açıklanmış. Hangi URI’a hangi metot ile request atmanız gerektiği belirtilmiş. Dışarıdaki geliştiricilerin API’yı keşfetmesi için tüm kapılar açık. PayPal gibi olmak lazım.

The HAL Browser sitesinden bununla ilgili örnek bir çalışmayı inceleyebilirsiniz.

Son olarak HAL ile çalışan bir kaç kütüphane de belirtmek istiyorum:

Spring Framework (Java)
Spring, HAL’i sevip bağrına basıyor ve in-build olarak destek sunuyor. Spring gibi olmak lazım. Kütüphaneye buradan erişebilirsiniz.

HALson (Typescript)
Node.js ile geliştirme yapıyorsanız HALson paketi bu konuda size yardımcı oluyor.

API Güvenliği

API’nızın her noktasının herkes tarafından sınırsızca kullanılmasını istemeyeceksinizdir. Bunun için neler yapabileceğimize bakalım ve örnek olarak da Riot Games’in API’ını inceleyelim.

Limitlendirme

Çoğu sistem belirli sürede atılan request miktarını sınırlar. Böylelikle sunucu yükü hafifletilir.

Riot Games’in API’ına 1 saniyede 21 request atarsanız 21. request’e cevap alamazsınız.

API Key

Çoğu sistem sizi diğer kullanıcılardan ayırt etmek için API key kullanır. Her kullanıcıya eşsiz bir API key verilir ve kullanıcılar her request attığında bu key’i de request’in belirli bir yerine koyar.

  1. Bu key bazen request’e parametre olarak verilir. Riot Games bunu yapıyor.
  2. Bazen de header’da tutulur. Bu header’ın adı ‘X-API-Key’ veya ‘Authorization’ olabilir. Her ikisi de kullanılır.
  3. Ayrıca body’e de koyabilirsiniz ancak pek tavsiye edilmez.

api_key parametresini girmezseniz, 401 Unauthorized hatası alırsınız. Dolayısıyla bu key sizin kimliğinizdir.

Örneğin bir API’da DELETE request’lerinin sadece yöneticiler tarafından kullanılabilmesini istiyorsanız bu api_key’ler ile kullanıcıları ayırt edebilir ve diğer kullanıcılara 401 Unauthorized response döndürürken, yöneticilere 200 OK dönmesini sağlayabilirsiniz.

HTTPS kullanın

Bildiğiniz üzere HTTPS, HTTP protokolünün güvenli hâlidir. TLS katmanıyla şifreleme ve güvenlik sağlar. Dolayısıyla her zaman HTTPS protokolünü tercih etmeniz önerilir.

HTTP Client’lar

Peki REST API’ınızı nasıl deneyebilirsiniz? Bunun için bir basit bir HTTP client yeterli. Genellikle Postman tercih edilir.

Postman

Postman, HTTP metodunu göndermenizi ve bunları kaydetmenizi sağlayan güzel bir tool’dur. Pek çok geliştirici tarafından tercih edilmesinden dolayı bazı şirketler burada kendi REST API collections’larını paylaşır. Böylece tek tıkla o şirketin tüm REST API’larını test etmeye hazır hâle gelebilirsiniz.

https://developer.paypal.com/api/rest/

Browser

Elbette, tüm tarayıcılar get request atmak için oluşturulmamış mıdır? GET request atmak için tek yapmanız gereken API’ınızın endpoint’ini tarayıcıya girmek. POST, PUT gibi metotları da request’lerinizde kullanmak için developer modunu açıp Network kısmına gidebilirsiniz.

cURL

Komut satırı üzerinden request atabilirsiniz. Örneğin GET request atmak için:

curl https://example.com/api/v1/endpoint

Komutunu kullanabilirsiniz ve elbette header’ların içini doldurmak, POST request atmak gibi işlemler yapmak da mümkün. Resmî rehber için burayı ziyaret edin.

Yazının sonuna geldik. Umarım faydalı olmuştur. Eleştiri, öneri veya herhangi bir konu için benimle iletişime geçebilirsiniz. Okuduğunuz için teşekkürler.

Kaynaklar

--

--