Modern web geliştirmede, Representational State Transfer (REST) API'leri, ölçeklenebilir, bakımı yapılabilir ve anlaşılması kolay web servisleri oluşturmak için fiili standart haline gelmiştir. Herhangi bir RESTful API'nin kalbinde temel bir kavram yatar: kaynak. Kaynakların ne olduğunu, nasıl tanımlandıklarını ve onlarla nasıl etkileşim kurduğumuzu anlamak, REST API'lerini etkili bir şekilde tasarlamak ve tüketmek için çok önemlidir. Bu makale, REST API'lerindeki kaynakların doğasına derinlemesine inecek, özelliklerini, koleksiyonlarla ilişkilerini ve üzerlerinde gerçekleştirilen yaygın işlemleri inceleyecektir.
REST'in arkasındaki temel fikir, bir API'nin bir dizi kaynak sunması ve istemcilerin bu kaynaklarla benzersiz tanımlayıcılarına istek göndererek etkileşim kurmasıdır. Ancak tam olarak bir "kaynak" neyi oluşturur? Bir REST API bağlamında, bir kaynak adlandırabileceğiniz hemen hemen her şey olabilir. Müşteri, ürün veya sipariş gibi somut bir varlık olabilir. Ayrıca bir hizmet, bir işlem veya bir hesaplama gibi soyut bir kavram da olabilir. Önemli olan, tanımlanabilen ve manipüle edilebilen bir ilgi alanıdır.
İnternetin kendisini geniş bir kaynak koleksiyonu olarak düşünün. Çevrimiçi eriştiğiniz her web sayfası, resim, video veya belge, her biri kendi benzersiz adresine (URL) sahip bir kaynaktır. REST API'leri de aynı felsefeyi benimser. İster bir sosyal medya platformundaki bir kullanıcı profili, ister çevrimiçi bir kitaplıktaki belirli bir kitap, ister belirli bir şehir için bir hava durumu tahmini olsun, her biri API'nin kullanılabilir hale getirdiği bir kaynaktır.
Geliştirici Ekibinizin maksimum verimlilikle birlikte çalışması için entegre, Hepsi Bir Arada bir platform mu istiyorsunuz?
Apidog tüm taleplerinizi karşılıyor ve Postman'in yerini çok daha uygun bir fiyata alıyor!
Kaynakları Tanımlama: URI'lerin Rolü
Önemli olarak, bir REST API'deki her kaynak en az bir benzersiz tanımlayıcıya sahip olmalıdır. Bu tanımlayıcı tipik olarak bir Uniform Resource Identifier (URI)'dir. Web API'lerinde kullanılan bir URI'nin en yaygın biçimi, yalnızca kaynağı tanımlamakla kalmayıp aynı zamanda onu bulmanın bir yolunu da sağlayan bir Uniform Resource Locator (URL)'dir.
Örneğin, bir blogu yönetmek için bir API'de, belirli bir blog yazısı /posts/123
gibi bir URI ile tanımlanabilir. Burada, /posts
muhtemelen bir gönderi koleksiyonunu temsil eder ve 123
, bu koleksiyondaki belirli bir gönderi için benzersiz tanımlayıcıdır. Benzer şekilde, bir kullanıcı kaynağı /users/john.doe
ile tanımlanabilir.
Bu URI'lerin tasarımı, API tasarımının kritik bir yönüdür. İyi tasarlanmış URI'ler sezgisel, tahmin edilebilir ve geliştiricilerin anlaması ve kullanması kolaydır. Erişilen kaynağın doğasını gösteren açık bir işaret görevi görmelidirler. İyi uygulama, kaynakları temsil etmek için fiiller yerine isimlerin (örneğin, /products
, /orders
) kullanılması gerektiğini belirtir (örneğin, /getProducts
, /createOrder
). Daha sonra HTTP yöntemleri (GET, POST, PUT, DELETE), URI tarafından tanımlanan kaynak üzerinde gerçekleştirilecek eylemi belirtmek için kullanılır.
Kaynak ve Temsil: Önemli Bir Ayrım
Bir kaynak ile temsili arasındaki farkı anlamak önemlidir. Bir kaynak, kavramsal varlığın kendisidir - gerçek "şey" (müşteri, ürün, fikir). Öte yandan, bir temsil, o kaynağın belirli bir zaman noktasındaki durumunun, tipik olarak JSON (JavaScript Object Notation) veya XML (eXtensible Markup Language) gibi belirli bir medya türünde biçimlendirilmiş bir anlık görüntüsüdür.
Bir istemci bir API'den bir kaynak istediğinde, kaynağın kendisini (sunucuda bulunan soyut bir kavram) almaz. Bunun yerine, o kaynağın bir temsilini alır. Örneğin, /users/jane.doe
talep ederseniz, API şu şekilde bir JSON temsili döndürebilir:JSON
{
"id": "jane.doe",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane.doe@example.com",
"dateJoined": "2023-01-15T10:00:00Z"
}
Bu JSON nesnesi Jane Doe'nun kendisi değildir; sistem tarafından depolandığı şekliyle verilerinin bir temsilidir. Aynı kaynak potansiyel olarak birden fazla temsile sahip olabilir. Örneğin, API, istemci tarafından içerik müzakeresi (Accept
gibi HTTP başlıkları kullanılarak) yoluyla talep edilirse, aynı kullanıcının bir XML temsilini de sağlayabilir.
Bir kaynağın durumu zaman içinde değişebilir. Jane Doe e-posta adresini güncellerse, temel kullanıcı kaynağı değişir. Daha sonra /users/jane.doe
için yapılan istekler, bu güncellenmiş durumu yansıtan yeni bir temsil döndürecektir. REST'in "Durum Aktarımı" kısmının devreye girdiği yer burasıdır: istemciler, bu temsiller aracılığıyla durumlarını alıp manipüle ederek kaynaklarla etkileşim kurar.
Koleksiyonlar: Diğer Kaynakları İçeren Kaynaklar
Genellikle, kaynaklar koleksiyonlar halinde gruplandırılır. Bir koleksiyonun kendisi bir kaynaktır. Örneğin, blog API'mizdeki /posts
, bireysel gönderi kaynaklarını içeren bir koleksiyon kaynağıdır. Benzer şekilde, /users
bir kullanıcı kaynakları koleksiyonu olacaktır.
Bir istemci, /products
gibi bir koleksiyon URI'sine bir GET isteği gönderdiğinde, API tipik olarak, genellikle her biri için bazı özet bilgilerle birlikte, o koleksiyondaki üye kaynakları listeleyen bir temsil döndürür. Bu liste şuna benzer olabilir:JSON
[
{
"id": "prod_abc",
"name": "Laptop Pro 15",
"price": 1299.99,
"link": "/products/prod_abc"
},
{
"id": "prod_xyz",
"name": "Wireless Mouse Ergonomic",
"price": 39.99,
"link": "/products/prod_xyz"
},
// ... more products
]
Koleksiyondaki her öğenin, istemcinin belirli bir ürünün tüm ayrıntılarına gitmesine ve bunları almasına olanak tanıyan, bireysel kaynağa bir bağlantı (veya kendi URI'si) içerdiğini fark edin.
Koleksiyonlar ve üyeleri için URI'lerin tasarlanması mantıksal bir kalıbı izler. Tipik olarak:
/resources
koleksiyona atıfta bulunur (örneğin,/orders
)./resources/{id}
o koleksiyondaki belirli bir üyeye atıfta bulunur (örneğin,/orders/567
).
Bu hiyerarşik yapı, API'yi sezgisel hale getirir ve koleksiyon ile öğeleri arasındaki kavramsal ilişkiyle uyumludur.
Kaynaklar ve Koleksiyonlar Üzerindeki İşlemler
Bir REST API'deki kaynaklar ve koleksiyonlarla etkileşim, standart HTTP yöntemleri aracılığıyla gerçekleştirilir. Bu yöntemler, gerçekleştirilecek eylemleri tanımlar. En yaygın yöntemler şunlardır:
GET: Bir kaynağın veya bir koleksiyonun bir temsilini almak için kullanılır.
GET /posts
tüm gönderilerin bir listesini (koleksiyon) alacaktır.GET /posts/123
, 123 kimlik numarasına sahip belirli gönderiyi alacaktır. GET istekleri güvenli olmalıdır, yani sunucu üzerinde herhangi bir yan etkiye sahip olmamalıdır; bunlar yalnızca veri almak içindir. Ayrıca idempotent olmalıdırlar, yani birden fazla özdeş GET isteği, tek bir istekle aynı etkiye sahip olmalıdır (yani, aynı temsili döndürmelidir, kaynağın bu arada değişmediğini varsayarak).
POST: Öncelikle bir koleksiyon içinde yeni bir kaynak oluşturmak için kullanılır. İstek gövdesi tipik olarak oluşturulacak yeni kaynağın temsilini içerir.
- Yeni bir blog gönderisinin (örneğin, başlık, içerik, yazar) ayrıntılarını içeren bir istek gövdesiyle
POST /posts
, sunucuya o yeni gönderiyi oluşturmasını emredecektir. Sunucu genellikle bir201 Created
durumuyla yanıt verir ve genellikle yanıtınLocation
başlığında yeni oluşturulan kaynağın URI'sini içerir. POST istekleri genellikle güvenli değildir (çünkü yeni bir kaynak oluştururlar) ve idempotent değildir (birden fazla özdeş POST isteği tipik olarak birden fazla yeni kaynak oluşturacaktır). POST, bir işlemi tetiklemek veya sonucu mevcut bir tanımlanabilir kaynağa yapılan bir güncelleme olmayan, işlenmek üzere veri göndermek gibi, diğer HTTP yöntemlerine tam olarak uymayan diğer idempotent olmayan işlemler için de kullanılabilir.
PUT: Mevcut bir kaynağı tamamen güncellemek için kullanılır. İstek gövdesi, kaynağın tam yeni temsilini içermelidir. URI tarafından tanımlanan kaynak varsa, yeni temsil ile değiştirilir. Yoksa, bazı API'ler onu oluşturmayı seçebilir (ancak bu davranış değişebilir).
- Gönderi 123 için güncellenmiş başlığı ve içeriği içeren bir istek gövdesiyle
PUT /posts/123
, mevcut gönderi 123'ü yeni verilerle değiştirecektir. PUT istekleri güvenli değildir (bir kaynağı değiştirdikleri için) ancak idempotenttir. Aynı PUT isteğini birden çok kez göndermek, kaynak için aynı duruma yol açmalıdır. Örneğin, bir gönderinin başlığını birden çok kez "Yeni Başlık" olarak güncellemek, yine de başlığın "Yeni Başlık" olmasıyla sonuçlanır.
DELETE: Bir kaynağı kaldırmak için kullanılır.
DELETE /posts/123
, 123 kimlik numarasına sahip blog gönderisini silecektir. DELETE istekleri güvenli değildir (veri kaldırdıkları için) ancak idempotenttir. Bir kaynağı birden çok kez silmek, onu bir kez silmekle aynı sonuca sahip olmalıdır (kaynak gitmiştir). Aynı URI'ye yapılan sonraki DELETE istekleri404 Not Found
veya204 No Content
döndürebilir.
PATCH: Mevcut bir kaynağı kısmen güncellemek için kullanılır. Kaynağın tüm temsilini göndermesini gerektiren PUT'tan farklı olarak, PATCH yalnızca değişiklikleri göndermeye izin verir. Örneğin, bir kullanıcının yalnızca e-posta adresini güncellemek için, bir PATCH isteğinin yalnızca yeni e-postayı içermesi gerekir.
{"email": "new.email@example.com"}
gibi bir istek gövdesiylePATCH /users/jane.doe
, yalnızca Jane'in e-posta adresini güncelleyecek ve adı gibi diğer alanları değiştirmeden bırakacaktır. PATCH istekleri güvenli değildir. İdempotensileri tartışılabilir ve yama işleminin doğasına bağlıdır. Örneğin, "açıklamaya '!' ekle" diyen bir PATCH işlemi idempotent değildir, "açıklamayı 'yeni değer' olarak ayarla" ise idempotenttir.
Tekil Kaynaklar
Koleksiyonlar ve üyeleri yaygın olmakla birlikte, bazen bir kaynak, genellikle bir "tekil" kaynak olarak adlandırılan, bağımsız bir varlıktır. İyi bir örnek, belirli bir uygulamanın yapılandırması veya bir sistemin mevcut durumu olabilir.
Örneğin, /application/configuration
, uygulamanın yapılandırma ayarlarını temsil eden bir tekil kaynak için bir URI olabilir. Bu URI'ye yapılan bir GET
isteği, mevcut yapılandırmayı alacak ve bir PUT
isteği onu güncellemek için kullanılabilir. Bu bağlamda bir "yapılandırma" "koleksiyonu" yoktur; sadece o yapılandırma vardır.
Benzer şekilde, /system/status
sistemin mevcut operasyonel durumunu temsil edebilir.
Kaynak Tabanlı API'ler Tasarlamak İçin En İyi Uygulamalar
Kaynak merkezli bir API tasarlamak, yalnızca varlıkları tanımlamaktan ve bunları URI'lere eşlemekten daha fazlasını içerir. Birkaç en iyi uygulama, sağlam ve kullanıcı dostu bir API'ye katkıda bulunur:
- URI'ler için İsimleri Kullanın: Daha önce belirtildiği gibi, kaynak URI'leri isimler olmalıdır (örneğin,
/products
,/users/{userId}/orders
). Fiiller HTTP yöntemleri için ayrılmalıdır. - Tutarlı URI Adlandırması: URI'leriniz için tutarlı bir adlandırma kuralı kullanın. Koleksiyonlar için genellikle çoğul isimler tercih edilir (örneğin,
/customer
yerine/customers
). Uzun yol segmentlerinin okunabilirliğini artırmak için kısa çizgiler (-
) kullanın (örneğin,/product-categories
), alt çizgiler (_
) veya camelCase yerine. - URI'leri Basit ve Hiyerarşik Tutun: Kaynaklar arasındaki ilişkileri yansıtan URI'ler tasarlayın. Örneğin,
/users/{userId}/accounts/{accountId}
, bir hesabın bir kullanıcıya ait olduğunu açıkça gösterir. Ancak, URI'leri hantal hale getirebilecek aşırı derin iç içe geçmelerden kaçının. - Durumsuzluk: Bir istemciden sunucuya yapılan her istek, isteği anlamak1 ve işlemek için gereken tüm bilgileri içermelidir. Sunucu2, istekler arasında herhangi bir istemci bağlamı saklamamalıdır. Bu, REST'in temel bir ilkesidir ve ölçeklenebilirliğe katkıda bulunur.
- HTTP Yöntemlerini Doğru Kullanın: GET, POST, PUT, DELETE ve PATCH'i tanımlanmış semantiklerine göre kullanın. Verileri değiştirmek için GET'i veya GET uygun olduğunda veri almak için POST'u kullanmayın.
- HTTP Durum Kodlarını Uygun Şekilde Kullanın: Bir isteğin sonucunu belirtmek için standart HTTP durum kodlarını döndürün (örneğin,
200 OK
,201 Created
,204 No Content
,400 Bad Request
,401 Unauthorized
,403 Forbidden
,3404 Not Found
,500 Internal Server Error
). Bu, istemciye net geri bildirim sağlar. - İçerik Müzakeresini Destekleyin: İstemcilerin,
Accept
başlığını kullanarak istenen temsil biçimini (örneğin, JSON, XML) belirtmesine veContent-Type
başlığını kullanarak istek gövdesinin biçimini belirtmesine izin verin. - Sürümlendirme: (örneğin,
/v1/products
) gibi bir sürümlendirme stratejisi uygulayarak API evrimi için plan yapın. Bu, mevcut istemcileri etkilemeden önemli değişiklikler yapmanıza olanak tanır. - Anlamlı Hata Temsilleri Sağlayın: Bir hata oluştuğunda, neyin yanlış gittiğini açıklayan yanıtta (tipik olarak JSON veya XML) faydalı bir hata mesajı döndürün.
- Uygulama Durumunun Motoru Olarak Hipermedya (HATEOAS): Her zaman tam olarak uygulanmasa da, HATEOAS REST'in temel bir ilkesidir. Bu, kaynakların temsillerinin, istemcilerin ilgili eylemleri ve kaynakları keşfetmesine olanak tanıyan bağlantılar (hipermedya kontrolleri) içermesi gerektiği anlamına gelir. Örneğin, bir siparişin temsili, siparişi iptal etmek, sevkiyat durumunu görüntülemek veya içerdiği ürünleri görmek için bağlantılar içerebilir. Bu, API'yi daha kendi kendine keşfedilebilir hale getirir.
Kaynakların Tanecikliği
Yaygın bir tasarım zorluğu, kaynaklarınızın uygun tanecikliğini belirlemektir. Bir adres ayrı bir kaynak mı olmalı, yoksa bir kullanıcı kaynağının parçası mı olmalı? Sipariş öğeleri farklı kaynaklar mı olmalı, yoksa bir sipariş kaynağına mı gömülmeli?
Tek bir doğru cevap yoktur; belirli kullanım durumlarına ve istemcilerin verilerle tipik olarak nasıl etkileşim kuracağına bağlıdır.
- Ayrı Kaynaklar: Bir varlık (bir adres gibi) bağımsız olarak oluşturulabiliyorsa, alınabiliyorsa, güncellenebiliyorsa veya silinebiliyorsa veya diğer birçok kaynak arasında paylaşılıyorsa, onu kendi URI'si olan ayrı bir kaynak olarak modellemek genellikle mantıklıdır (örneğin,
/addresses/{addressId}
). Daha sonra onu diğer kaynaklardan (örneğin, bir kullanıcı kaynağı biraddressId
alanına veya/addresses/{addressId}
bağlantısına sahip olabilir) bağlayabilirsiniz. - Gömülü Kaynaklar/Alt Kaynaklar: Bir varlık bir üst kaynakla sıkı bir şekilde bağlantılıysa ve bağımsız bir yaşam döngüsüne sahip değilse, üst kaynağın temsilinin bir parçası olarak veya
/users/{userId}/address
gibi bir yol aracılığıyla erişilebilen bir alt kaynak olarak modellenmesi daha iyi olabilir. Bu, alt varlığa her zaman üstünün bağlamında erişiliyorsa, istemci etkileşimlerini basitleştirebilir.
Seçim genellikle değiş tokuşları içerir:
- Konuşkanlık: Birçok ince taneli kaynak, bir istemcinin birden çok kaynaktan eksiksiz bir resim oluşturması gerekiyorsa, daha fazla HTTP isteğine (artırılmış konuşkanlık) yol açabilir.
- Veri Çoğaltma/Karmaşıklık: Kaynakları gömmek, daha büyük yüklemelere ve gömülü bilgiler bağımsız bir kaynak olarak da mevcutsa potansiyel veri çoğaltmaya veya karmaşıklığa yol açabilir.
- Önbelleğe Alma: Ayrı kaynaklar genellikle bağımsız olarak önbelleğe alınması daha kolaydır.
- İşlemlerin Atomikliği: Tek, kaba taneli bir kaynağa yapılan güncellemeler doğal olarak atomiktir. Birden çok ince taneli kaynak güncellemesi genelinde atomikliği yönetmek daha karmaşık olabilir.
API'nin nasıl kullanılacağına dair derin bir anlayışla birlikte, bu faktörlerin dikkatli bir şekilde değerlendirilmesi, kaynak tanecikliği hakkında doğru kararlar vermek için çok önemlidir.
Geliştirici Ekibinizin maksimum verimlilikle birlikte çalışması için entegre, Hepsi Bir Arada bir platform mu istiyorsunuz?
Apidog tüm taleplerinizi karşılıyor ve Postman'in yerini çok daha uygun bir fiyata alıyor!
Sonuç
Kaynaklar, herhangi bir RESTful API'nin temel yapı taşlarıdır. Bir API'nin sunduğu ve istemcilerin etkileşim kurmasına izin verdiği "şeyleri" temsil ederler. Geliştiriciler, kaynaklara benzersiz URI'ler atayarak, bir kaynak ile temsili arasında ayrım yaparak ve kaynakları mantıksal koleksiyonlar halinde düzenleyerek, sezgisel, ölçeklenebilir ve REST ilkelerine uyan API'ler oluşturabilirler.
Standart HTTP yöntemlerini kullanarak kaynakları nasıl tanımlayacağınızı, tanımlayacağınızı ve manipüle edeceğinizi anlamak, hem API tasarımcıları hem de tüketiciler için çok önemlidir. URI tasarımında en iyi uygulamalar, HTTP durum kodlarının uygun kullanımı ve kaynak tanecikliğine yönelik düşünceli bir yaklaşımla birleştiğinde, iyi tanımlanmış bir kaynak modeli, yalnızca işlevsel değil, aynı zamanda çalışmaktan keyif alınan API'lere yol açar. Dijital ortam gelişmeye devam ettikçe, kaynak odaklı mimarinin ilkeleri, etkili web hizmeti iletişiminin bir köşetaşı olmaya devam edecektir.