geri

Herkes RESTful Web API tasarlayabilir

06/04/2012

Herkes RESTful Web API tasarlayabilir ama bazı kurallara uymak koşuluyla...

Geçenlerde Twitter'da kaynağını tam olarak bilemediğim fakat çok beğendiğim bir tweet dolaştı.

HTTP response codes for dummies. 50x: we fucked up. 40x: you fucked up. 30x: ask that dude over there. 20x: cool.

Kısmen usturuplu Türkçe çevirisi şöyle:

Zor öğrenenler için HTTP durum kodları. 50x: biz sıçtık. 40x: sen sıçtın. 30x: şu karşıdaki elemana sor. 20x: tamamdır.

HTTP durum kodları bundan daha iyi anlatılamazdı sanırım. Bu tweetten bir zaman sonra Karl Seguin'in şu tweeti geldi. Kısaca söylediği şuydu: web servisiniz hataları neden 200 durum kodu ile döndürüyor?

Bu iki tweet RESTful Web API geliştiricileri için önemli ipuçları veriyor. Ben de kendi tecrübelerim ışığında bir RESTful Web API'nin nasıl tasarlanması gerektiğinden bahsetmeye çalışacağım. Anlatacaklarımın %100 geçerli ya da doğru olmasını beklemek büyük bir yanılgı olur. Bu sebeple bu yazıyı bir tür başlangıç noktası olarak değerlendirmenizi öneririm.

Hangi durumda hangi HTTP metodu kullanılmalı?

HTTP Metodu Açıklama
HEAD HEAD metodu ile yapılan isteklere verilen yanıt içeriği boştur. Geriye yalnızca HTTP Yanıt Başlıkları ve durum kodu döner. Bu metod ile servis sağlayıcı hakkında bilgi alınabilir ya da bir kaynağın varlığı doğrulanabilir.
GET GET metodunu bir kaynağın ayrıntılarına ulaşmak için kullanabilirsiniz. Buna örnek olarak 1 ID'li kullanıcının bilgilerini verebiliriz.
POST POST metodu ile servis sağlayıcı üzerinde yeni bir kaynak oluşturabilirsiniz. Yine örnek olarak yeni bir kullanıcı oluşturmayı verebiliriz. Kaynağı güncellemek için ben PUT metodunu öneriyorum. Bu sebeple genelde POST metodu ile kaynak ID'sini göndermeye gerek yoktur. ID, servis sağlayıcı tarafından oluşturulmalıdır.
PUT PUT metodu ile servis sağlayıcı üzerindeki bir kaynağı güncelleyebilirsiniz. Hangi kaynağın güncelleneceğini belirtmek için kaynağın ID'si servis sağlayıcıya gönderilmelidir.
DELETE DELETE metodunu bir kaynağı silmek için kullanabilirsiniz. Hangi kaynağın silineceğini belirtmek için kaynağın ID'si servis sağlayıcıya gönderilmelidir. ID belirtilmezse tüm kaynakların silinmesi de sağlanabilir. Ancak bu durum dikkatle gerçeklenmelidir.

HTTP metodlarını kullanırken dikkat edilmesi gereken belki en önemli nokta HEAD ve GET metodlarının salt okunur olması gereğidir. Başka bir deyişle HEAD ve GET metodları ile kaynak bilgilerini güncellememeli ya da yeni kaynak oluşturmamalısınız. Yazma işleri için POST, PUT ve DELETE metodlarını kullanmalısınız. Diğer yandan PUT ve DELETE metodları idempotent metodlardır. Bu sebeple art arda çağrılmaları sorun oluşturmaz/oluşturmamalıdır.

URI'ler nasıl olmalı?

Google'da arama yaparsanız bu konuda pek çok farklı öneriye/gerçeklemeye ulaşabilirsiniz. Ben de kendi önerilerimi sıralayacağım. Wikipedia'da yapılan açıklama oldukça güzel. Benim önerilerim de bu tabloya benzer olacak.

URI'leriniz ID dışında parametre içermemeli.

Parametreleri URI içine yazdığınızda URI'leriniz yönetilemez bir hale gelecektir. Bir örnek vereyim:

GET /api/{TICKET}/{DOMAIN}/users/{ROLE}/

Bu API ile belli bir etki alanında(DOMAIN) belli bir role(ROLE) sahip olan kullanıcıların sorgulandığını varsayalım. TICKET parametresinin ise güvenlik amacılığıyla gönderilen bir anahtar olduğunu kabul edelim. Bu URI'nin istemci tarafında oluşturulması oldukça zordur. Bu sebeple ben ID parametresi dışındaki parametrelerin URI'de bulunmasını pratikte çok uygun bulmuyorum. Buna bir istisna olarak örnekteki TICKET parametresini verebilirim. Eğer TICKET parametresi her URI'de bulunacak ise (bu tür parametrelere statik parametre diyorum) bu URI'lerin istemci tarafında ortak bir kod ile oluşturulması pek zor olmayacaktır. Bunun diğer bir faydası da TICKET içermeyen istekler için doğrudan HTTP 404 döndürülebilmesine imkan sağlamasıdır. Sonuç olarak önerilerim doğrultusunda yukarıdaki URI şu hale gelmelidir.

GET /api/{TICKET}/users?domain=...&role=...
URI'lerde büyük harf kullanılmamalı.

Bu önerimin nesnel bir açıklaması yok ama genel kullanımda /dailySessions yerine /daily_sessions ya da /sessions/daily kullanımı daha düzgün ve kolay görünüyor.

Hangi durumda hangi HTTP durum kodu kullanılmalı?

Yazının başında verdiğim tweet örneği durum kodlarını oldukça iyi açıklıyor. 50x durum kodları servis sağlayıcı tarafında bir hata olduğuna, 40x durum kodları istemci tarafında bir hata olduğuna işaret ediyor. 20x durum kodları ise isteğin başarıyla sonuçladığını ifade ediyor. Bu sebeple hata mesajları asla ve asla 20x durum kodu ile gönderilmemelidir. Hata türüne uygun durum kodu seçilerek hata mesajı bu durum kodu ile istemciye gönderilmelidir. Oldukça fazla sayıda durum kodu olsa da ben 200, 400, 403, 404 ve 500 durum kodlarını yeterli buluyorum. Ama belli durumlarda diğer durum kodlarını kullanma gereği olabileceğini de aklınızdan çıkarmayın derim.

HTTP Durum Kodu Açıklama
200 İşlemin başarıyla gerçekleştiğini belirtir. Yalnızca başarı durumunda kullanılmalıdır.
400 İsteğin geçersiz olduğunu belirtir. Eksik bir parametre ya da parametrenin hatalı olması durumunda kullanmanızı öneririm.
403 İstemcinin bu kaynağa erişiminin yasak olduğunu belirtir. Kendi kendini açıklıyor.
404 İstenen kaynağın bulunamadığı anlamına gelir. Örnek olarak belirtilen ID'ye sahip kullanıcı yok ise bu kodu kullanabilirsiniz.
500 Servis sağlayıcıda beklenmeyen bir hata olduğunda bu kodu kullanmalısınız.

Durum kodu ile birlikte hata mesajı gönderme zorunluluğunuz bulunmasa da hata mesajı vermek API kullanıcılarının işini oldukça kolaylaştıracaktır. Bu sebeple 400, 403, 404 ve 500 durum kodları ile birlikte mutlaka hata mesajı dönmenizi öneririm.

Yanıt hangi formatta olmalı?

Yanıt için yeni bir format keşfetmenize inanın hiç gerek yok. JSON formatı hem güzel, hem parse edilmesi kolay, hem de çok fazla kütüphane desteğine sahiptir. Bu sebeple yanıtlarınızı aksi çok gerekli olmadıkça JSON formatında dönmenizi öneririm.

JSONP ve CORS

Bu iki yöntemin ayrıntılarına burada değinmeyeceğim ama geliştirdiğiniz API Javascript istemciler ile kullanılacaksa iki yönteme de destek vermeniz yerinde olacaktır.

Buraya kadar sabırla okuduğunuz için teşekkür ederim. Umarım faydalı olmuştur.

Follow me on Twitter