REST'i anlama: Fiiller, hata kodları ve kimlik doğrulama


602

Ben PHP tabanlı web uygulamaları, veritabanları ve CMS'lerde varsayılan işlevleri etrafında API'leri sarmak için bir yol arıyorum.

Etrafa baktım ve birkaç "iskelet" çerçevesi buldum. Sorumdaki cevaplara ek olarak , çok hafif olduğu için beğendiğim bir REST çerçevesi olan Tonic var .

REST'i sadeliği için en iyisini seviyorum ve buna dayalı bir API mimarisi oluşturmak istiyorum. Kafamı temel ilkeler etrafında bulmaya çalışıyorum ve henüz tam olarak anlayamadım. Bu nedenle, bir dizi soru.

1. Doğru anladım mı?

"Kullanıcılar" kaynağım olduğunu varsayalım. Ben böyle URI bir dizi kurabilir:

/api/users     when called with GET, lists users
/api/users     when called with POST, creates user record
/api/users/1   when called with GET, shows user record
               when called with PUT, updates user record
               when called with DELETE, deletes user record

bu şimdiye kadar RESTful mimarisinin doğru bir temsili midir?

2. Daha fazla fiile ihtiyacım var

Oluşturma, Güncelleme ve Silme teoride yeterli olabilir, ancak pratikte çok daha fazla fiile ihtiyacım olacak. O şeylerin farkına olabilir bir güncelleme isteğinde gömülebilir, ancak özel dönüş kodları olabilir belirli eylemleri vardır ve ben bir eyleme hepsini atmak istemem.

Kullanıcı örneğinde akla gelen bazıları:

activate_login
deactivate_login
change_password
add_credit

RESTful URL mimarisindeki eylemler gibi işlemleri nasıl ifade ederim?

İçgüdüm şöyle bir URL'ye GET çağrısı yapmak olacak

/api/users/1/activate_login 

ve bir durum kodu geri bekliyoruz.

Ancak bu, HTTP fiillerini kullanma fikrinden sapmaktadır. Ne düşünüyorsun?

3. Hata mesajları ve kodları nasıl iade edilir

REST'in güzelliğinin büyük bir kısmı, standart HTTP yöntemlerini kullanmasından kaynaklanmaktadır. Bir hata durumunda, 3xx, 4xx veya 5xx hata durum koduna sahip bir başlık yayarım. Ayrıntılı bir hata açıklaması için gövdeyi kullanabilirim (değil mi?). Çok uzak çok iyi. Ancak, neyin yanlış gittiğini (ör. "Veritabanına bağlanılamadı" veya "veritabanı girişi yanlış") daha ayrıntılı olarak açıklayan tescilli bir hata kodu iletmenin yolu ne olabilir ? Mesajla birlikte vücuda koyarsam, daha sonra ayrıştırmam gerekir. Bu tür şeyler için standart bir başlık var mı?

4. Kimlik doğrulama nasıl yapılır

  • REST ilkelerini izleyen bir API anahtar tabanlı kimlik doğrulaması nasıl görünür?
  • Bir REST istemcisinin kimliğini doğrularken oturumların kullanılmasına karşı güçlü noktalar var, bunun dışında REST ilkesinin açık bir ihlali var mı? :) (burada sadece yarısı şaka yapıyorum, oturum tabanlı kimlik doğrulaması mevcut altyapımla iyi oynayacaktır.)

13
@ Daniel, düzenleme için teşekkürler. "Ben daha fazla fiil" kasıtlı bir cinstir, ama olduğu gibi bırakıyorum, şimdi okumak daha kolay. :)
Pekka

1
BTW, hata açıklaması hakkında. Yanıtın başlığına hata açıklaması koymakla sonuçlandım. 'Hata Açıklaması' adlı bir başlık eklemeniz yeterlidir.
Andrii Muzychuk

Bu daha çok uygulama güvenliği sorularına benziyor. Uygulama güvenliği REST'in konusu değildir.
Nazar Merza

@NazarMerza 1., 2. ve 3. uygulama güvenlik soruları nelerdir?
Pekka

Yanıtlar:


621

Bu soruyu birkaç gün geç fark ettim, ama içgörüler ekleyebileceğimi hissediyorum. Umarım bu sizin RESTful girişiminize yardımcı olabilir.


Nokta 1: Doğru mu anlıyorum?

Doğru anladın. Bu bir RESTful mimarisinin doğru bir temsilidir. Wikipedia'daki aşağıdaki matrisi , adlarınızı ve fiillerinizi tanımlamak için çok yararlı bulabilirsiniz :


Gibi bir Koleksiyon URI ile uğraşırken :http://example.com/resources/

  • GET : Daha fazla gezinme için koleksiyonun üyelerini, üye URI'leriyle birlikte listeleyin. Örneğin, satılık tüm arabaları listeleyin.

  • PUT : "Tüm koleksiyonu başka bir koleksiyonla değiştir" olarak tanımlanan anlam.

  • POST : Koleksiyonda, kimliğin koleksiyon tarafından otomatik olarak atandığı yeni bir giriş oluşturun. Oluşturulan kimlik genellikle bu işlem tarafından döndürülen verilerin bir parçası olarak eklenir.

  • DELETE : "Tüm koleksiyonu sil" olarak tanımlanan anlam.


Aşağıdaki gibi bir Üye URI ile uğraşırken :http://example.com/resources/7HOU57Y

  • GET : Koleksiyonun adreslenen üyesinin uygun bir MIME türünde ifade edilen bir temsilini alın.

  • PUT : Koleksiyonun adreslenen üyesini güncelleyin veya belirtilen kimlikle oluşturun.

  • POST : Ele alınan üyeye kendi başına bir koleksiyon olarak davranır ve yeni bir ast oluşturur.

  • SİL : Koleksiyonun adreslenen üyesini silin.


2. Nokta: Daha fazla fiile ihtiyacım var

Genel olarak, daha fazla fiile ihtiyacınız olduğunu düşündüğünüzde, aslında kaynaklarınızın yeniden tanımlanması gerektiği anlamına gelebilir. REST'te her zaman bir kaynak veya bir kaynak koleksiyonu üzerinde hareket ettiğinizi unutmayın. Kaynak olarak seçtiğiniz şey API tanımınız için oldukça önemlidir.

Oturum Açmayı Etkinleştirme / Devre Dışı Bırakma : Yeni bir oturum oluşturuyorsanız, kaynak olarak "oturumu" dikkate almak isteyebilirsiniz. Yeni bir oturum oluşturmak için POST'u kullanarak http://example.com/sessions/gövdedeki kimlik bilgilerini kullanın . Süresi dolmak için PUT veya bir DELETE kullanın (belki bir oturum geçmişini tutmak isteyip istemediğinize bağlı olarak) http://example.com/sessions/SESSION_ID.

Parolayı Değiştir: Bu sefer kaynak "kullanıcı" dır. http://example.com/users/USER_IDVücuttaki eski ve yeni parolalarla bir PUT'a ihtiyacınız olacaktır . "Kullanıcı" kaynağı üzerinde işlem yapıyorsunuz ve değişiklik şifresi basitçe bir güncelleme isteğidir. İlişkisel bir veritabanındaki UPDATE deyimine oldukça benzer.

İçgüdüm şöyle bir URL'ye GET çağrısı yapmak olacak /api/users/1/activate_login

Bu çok temel bir REST prensibine aykırıdır: HTTP fiillerinin doğru kullanımı. Herhangi bir GET talebi hiçbir zaman yan etki bırakmamalıdır.

Örneğin, bir GET isteği hiçbir zaman veritabanında bir oturum oluşturmamalı, yeni bir Oturum Kimliği ile bir çerez döndürmemeli veya sunucuda herhangi bir kalıntı bırakmamalıdır. GET fiili bir veritabanı motorundaki SELECT deyimine benzer. GET fiili ile yapılan herhangi bir talebe verilen yanıtın, tıpkı statik bir web sayfası talep ettiğiniz gibi, aynı parametrelerle istendiğinde önbelleğe alınabilmesi gerektiğini unutmayın.


Nokta 3: Hata mesajları ve kodları nasıl döndürülür

Hata kategorileri olarak 4xx veya 5xx HTTP durum kodlarını düşünün. Vücuttaki hatayı açıklayabilirsiniz.

Veritabanına Bağlanılamadı: / Hatalı Veritabanı Girişi : Genel olarak bu tür hatalar için 500 hatası kullanmalısınız. Bu bir sunucu tarafı hatasıdır. Müşteri yanlış bir şey yapmadı. 500 hata normal olarak "yeniden denenebilir" olarak değerlendirilir. yani, istemci aynı isteği yeniden deneyebilir ve sunucunun sorunları çözüldükten sonra başarılı olmasını bekleyebilir. Vücuttaki ayrıntıları belirtin, böylece müşteri bize insanlara bir bağlam sağlayabilir.

Diğer hata kategorisi, genel olarak müşterinin yanlış bir şey yaptığını gösteren 4xx ailesi olacaktır. Özellikle, bu hata kategorisi normalde istemciye isteği olduğu gibi yeniden denemeye gerek olmadığını gösterir, çünkü kalıcı olarak başarısız olmaya devam edecektir. yani, müşterinin bu isteği yeniden denemeden önce bir şeyi değiştirmesi gerekir. Örneğin, "Kaynak bulunamadı" (HTTP 404) veya "Hatalı Biçimlendirilmiş İstek" (HTTP 400) hataları bu kategoriye girer.


Nokta 4: Kimlik doğrulama nasıl yapılır

1. maddede belirtildiği gibi, bir kullanıcının kimliğini doğrulamak yerine, bir oturum oluşturmayı düşünmek isteyebilirsiniz. Uygun HTTP durum kodu ile birlikte yeni bir "Oturum Kimliği" döndürüleceksiniz (200: Erişim İzni Verildi veya 403: Erişim Reddedildi).

Daha sonra RESTful sunucunuza şu soruyu soracaksınız: "Bana bu Oturum Kimliği için kaynağı ALABİLİR MİSİNİZ?"

Kimliği doğrulanmış bir mod yoktur - REST vatansızdır: Bir oturum oluşturursunuz, sunucudan bu Oturum Kimliğini parametre olarak kullanarak size kaynak vermesini istersiniz ve oturum kapatıldığında oturumu bırakırsınız veya sona erdirirsiniz.


6
Çok iyi, ancak PUTbir şifreyi değiştirmek için kullanmanız muhtemelen yanlış; PUTkaynağın tamamını gerektirir, bu nedenle HTTP'ye (ve dolayısıyla HATEOAS REST'e) uymak için tüm kullanıcı özelliklerini göndermeniz gerekir. Aksine, sadece şifresini değiştirmek için PATCHveya kullanmalısınız POST.
Lawrence Dol

1
Ben "POST: ele alınan üyeye kendi başına bir koleksiyon olarak davranır ve yeni bir ast oluşturur" daha fazla genişletirseniz bu yazı mükemmel olacağını düşünüyorum. anlamına geliyor. - Googling ile bunun ne anlama geldiğini buldum - aksi takdirde büyük cevabınıza bir istisna oluşturur.
Martin Konecny

6
Son cümleyi kabul etmiyorum. REST'in vatansız olduğunu açıklıyorsunuz. Bir oturum oluşturmak için oturum açmak, ardından bazı işler yaptıktan sonra oturumu sonlandırmak için oturum kapatmak durum bilgisi olan bir API'nin en iyi örneğidir.
Brandon

1
"Bu çok temel bir REST ilkesine aykırıdır: HTTP fiillerinin doğru kullanımı. Herhangi bir GET isteği hiçbir zaman yan etki bırakmamalıdır." - Ya kaynak için isabet sayısını korumak isterseniz?
bobbyalex

1
Bu makale sorularınızı cevaplamalıdır. saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices
java_geek

79

Basitçe söylemek gerekirse, bunu tamamen geri yapıyorsunuz.

Hangi URL'leri kullanmanız gerektiğine yaklaşmamalısınız. Sisteminiz için hangi kaynakların gerekli olduğuna ve bu kaynakları nasıl temsil edeceğinize ve kaynaklar ile uygulama durumu arasındaki etkileşimlere karar verdikten sonra URL'ler etkili bir şekilde "ücretsiz" olarak gelir.

Roy Fielding'i alıntılamak için

Bir REST API, neredeyse tüm açıklayıcı çabalarını kaynakları temsil etmek ve uygulama durumunu göstermek için kullanılan medya türlerini tanımlamak veya mevcut standart medya türleri için genişletilmiş ilişki adları ve / veya hipermetin özellikli işaretleme tanımlamak için harcamalıdır. Hangi URI'lerde hangi yöntemlerin kullanılacağını tanımlamak için harcanan her türlü çaba, bir medya türü için (ve çoğu durumda zaten mevcut medya türleri tarafından tanımlanmış) işleme kuralları kapsamında tanımlanmalıdır. [Buradaki başarısızlık, bant dışı bilginin köprü metni yerine etkileşimi tetiklediğini gösterir.]

İnsanlar her zaman URI'lerle başlar ve bunun bir çözüm olduğunu düşünürler ve daha sonra REST mimarisinde önemli bir kavramı gözden kaçırırlar. "

Dürüst olmak gerekirse, birçoğu bir grup URI ve bazı GET'ler ve PUT'lar ve POST'lar görür ve REST'in kolay olduğunu düşünür. REST kolay değil. HTTP üzerinden RPC kolaydır, veri yüklerini HTTP faydalı yükleri aracılığıyla vekil olarak ileri geri taşımak kolaydır. Ancak REST bunun ötesine geçer. REST protokol agnostiktir. HTTP sadece çok popüler ve REST sistemleri için uygundur.

REST, medya türlerinde, tanımlarında ve uygulamanın hipermetin (bağlantılar, etkin) aracılığıyla bu kaynaklar için kullanılabilir eylemleri nasıl yönlendirdiğini yaşar.

REST sistemlerinde medya türleri hakkında farklı görüşler vardır. Bazıları uygulamaya özgü faydalı yükleri desteklerken, diğerleri mevcut medya türlerini uygulamaya uygun rollere yükseltmeyi sever. Örneğin, bir yandan, örneğin mikro biçimler ve diğer mekanizmalar aracılığıyla, temsiliniz olarak XHTML gibi bir şeyi kullanmaya karşı uygulamanıza uygun olarak tasarlanmış belirli XML şemalarınız vardır.

Her iki yaklaşımın da yeri var, bence XHTML hem insan güdümlü hem de makine güdümlü web ile örtüşen senaryolarda çok iyi çalışıyorken, daha eski, daha spesifik veri türlerinin makine-makine etkileşimlerini daha iyi kolaylaştırdığını hissediyorum. Emtia formatlarının canlandırılmasının içerik pazarlığını potansiyel olarak zorlaştırabileceğini düşünüyorum. "application / xml + yourresource", bir medya istemcisi olarak "application / xhtml + xml" den çok daha belirgindir, çünkü ikincisi, bir makine istemcisinin gerçekten ilgilendiği veya olmayabileceği birçok yüke uygulanabilir içgözlem olmadan belirlemek.

Bununla birlikte, XHTML, web tarayıcılarının ve oluşturmanın çok önemli olduğu insan ağında çok iyi çalışır (açıkçası).

Başvurunuz bu tür kararlarda size rehberlik edecektir.

Bir REST sistemi tasarlama sürecinin bir kısmı, sisteminizdeki birinci sınıf kaynakları ve birincil kaynaklardaki işlemleri desteklemek için gerekli türev, destek kaynaklarını keşfetmektir. Kaynaklar keşfedildikten sonra, bu kaynakların temsili ve bir sonraki zorluk nedeniyle temsillerde hipermetin üzerinden kaynak akışını gösteren durum diyagramları.

Bir metnin köprü metni sistemindeki her gösteriminin, hem gerçek kaynak gösterimini hem de kaynak için kullanılabilir durum geçişlerini birleştirdiğini hatırlayın. Her bir kaynağı grafikteki bir düğüm olarak düşünün; bağlantılar bu düğümü diğer düğümlere bırakan satırlardır. Bu bağlantılar, istemcilere yalnızca neler yapılabileceğini değil, bunların yapılması için ne yapılması gerektiğini de bildirir (iyi bir bağlantı olarak URI ve gereken ortam türünü birleştirir).

Örneğin, şunlara sahip olabilirsiniz:

<link href="http://example.com/users" rel="users" type="application/xml+usercollection"/>
<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>

Belgeleriniz "kullanıcılar" adlı rel alanı ve "application / xml + youruser" ortam türü hakkında konuşacaktır.

Bu bağlantılar gereksiz görünebilir, hepsi aynı URI ile konuşuyor, hemen hemen. Ama değiller.

Bunun nedeni, "kullanıcılar" ilişkisi için, bu bağlantının kullanıcı koleksiyonu hakkında konuşmasıdır ve koleksiyonla çalışmak için tek biçimli arayüzü kullanabilirsiniz (hepsini almak için GET, hepsini silmek için DELETE, vb.)

Bu URL'ye POST yaparsanız, büyük olasılıkla belgede yalnızca tek bir kullanıcı örneği içerecek şekilde "application / xml + usercollection" belgesini iletmeniz gerekir; böylece kullanıcıyı ekleyebilir veya bir Zamanlar. Belki de belgeleriniz, koleksiyon yerine tek bir kullanıcı türünü geçebilmenizi önerecektir.

"Arama" bağlantısı ve arabuluculuk ile tanımlandığı gibi, bir arama yapmak için uygulamanın neye ihtiyaç duyduğunu görebilirsiniz. Arama medyası türüyle ilgili belgeler size bunun nasıl davrandığını ve sonuç olarak ne bekleyeceğinizi gösterecektir.

Buradaki paket servisi, URI'lerin kendilerinin temelde önemsiz olmasıdır. Uygulama istemcileri değil URI'leri kontrol ediyor. Birkaç 'giriş noktasının' ötesinde, müşterilerinizin çalışması için uygulamanın sağladığı URI'lara güvenmesi gerekir.

Müşteri, medya türlerini nasıl manipüle edeceğini ve yorumlayacağını bilmelidir, ancak nereye gittiğine dikkat etmek gerekmez.

Bu iki bağlantı bir müşterinin gözünde anlamsal olarak aynıdır:

<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
<link href="http://example.com/AW163FH87SGV" rel="search" type="application/xml+usersearchcriteria"/>

Yani, kaynaklarınıza odaklanın. Uygulamadaki durum geçişlerine ve bunun en iyi nasıl elde edildiğine odaklanın.


1
Bu çok derin cevap için teşekkürler Will. Birkaç puan alınır. "URL'nin neye benzediğini" planlamanın bunu tam tersine yaptığının farkındayım ve kaynak tarafında da planlıyorum. Oynatılacak URL'lere sahip olmak, konsepti anlamamı kolaylaştırıyor. Bu olabilir benim gereksinimleri burada tanımladığı anlamda değil% 100 takip DİNLENME ilkelerini yapan bir sistemle yerine getirileceğini ol. Her kaynak türü için gereksinimlerin tam bir listesini hazırlayacağım, sanırım o zaman karar verebilirim. Şerefe.
Pekka

30

re 1 : Bu şimdiye kadar iyi görünüyor. Yeni oluşturulan kullanıcının URI'sini "201 Oluşturuldu" durum koduyla birlikte POST yanıtının bir parçası olarak bir "Konum:" başlığına döndürmeyi unutmayın.

re 2: GET aracılığıyla etkinleştirme kötü bir fikirdir ve URI'ye fiil dahil etmek bir tasarım kokusudur. Bir GET'te form döndürmeyi düşünebilirsiniz. Bir Web uygulamasında bu, gönder düğmesi olan bir HTML formu olacaktır; API kullanım durumunda, hesabı etkinleştirmek için PUT'a bir URI içeren bir gösterim döndürmek isteyebilirsiniz. Elbette bu URI'yi POST kullanıcılarına / kullanıcılarına yanıta da dahil edebilirsiniz. PUT kullanılması, isteğinizin idempotent olmasını sağlar, yani müşteri başarı konusunda emin değilse tekrar güvenli bir şekilde gönderilebilir. Genel olarak, fiillerinizi hangi kaynaklara dönüştürebileceğinizi düşünün (bir çeşit "fiillerin nounifikasyonu"). Kendinize, özel eyleminizin hangi yöntemle en uyumlu olduğunu sorun. Örneğin change_password -> PUT; devre dışı bırak -> muhtemelen SİL; add_credit -> muhtemelen POST veya PUT.

re 3. Yeni durum kodları icat etmeyin, bu kadar genel olduklarına inanmıyorsanız, küresel olarak standartlaştırılmayı hak ediyorlar. Mevcut en uygun durum kodunu kullanmayı deneyin (RFC 2616'da hepsini okuyun). Yanıt gövdesine ek bilgi ekleyin. Gerçekten, gerçekten yeni bir durum kodu icat etmek istediğinizden eminseniz, tekrar düşünün; hala inanıyorsanız, en azından doğru kategoriyi seçtiğinizden emin olun (1xx -> OK, 2xx -> bilgi amaçlı, 3xx -> yönlendirme; 4xx-> istemci hatası, 5xx -> sunucu hatası). Yeni durum kodları icat etmenin kötü bir fikir olduğunu söylemiş miydim?

re 4. Mümkünse, HTTP'de yerleşik olan kimlik doğrulama çerçevesini kullanın. Google'ın GData'da kimlik doğrulamasını nasıl yaptığına bakın. Genel olarak, URI'lerinize API anahtarları koymayın. Ölçeklenebilirliği artırmak ve önbelleğe almayı desteklemek için oturumlardan kaçınmaya çalışın - bir isteğe yanıt daha önce olan bir şey nedeniyle farklılık gösterirse, genellikle kendinizi belirli bir sunucu işlemi örneğine bağlarsınız. Oturum durumunu ya istemci durumuna çevirmek (örneğin sonraki isteklerin bir parçası haline getirmek) ya da (sunucu) kaynak durumuna çevirerek açık hale getirmek, yani kendi URI'sini vermek daha iyidir.


URL'lere neden API anahtarları koymamanızı tartışabilir misiniz? Proxy günlüklerinde görünür oldukları için mi? Anahtarlar geçici, zamana dayalıysa ne olur? HTTPS kullanılırsa ne olur?
MikeSchinkel

4
Ruhu ihlal etmenin yanı sıra (URI'ler bir şeyleri tanımlamalıdır), ana sonuç, önbelleğe almayı bozmasıdır.
Stefan Tilkov

22

1. Kaynaklarınızı nasıl tasarlayacağınız konusunda doğru fikriniz var IMHO. Hiçbir şeyi değiştirmezdim.

2. HTTP'yi daha fazla fiil ile genişletmeye çalışmak yerine, önerilen fiillerin temel HTTP yöntemleri ve kaynakları açısından neye indirgenebileceğini düşünün. Örneğin, bir activate_loginfiil yerine, aşağıdakiler gibi kaynaklar ayarlayabilirsiniz: /api/users/1/login/activeki bu basit bir boole'dir. Bir girişi etkinleştirmek için, PUTorada sadece 'doğru' veya 1 ya da her neyse yazan bir belge var. Devre dışı bırakmak için, PUTorada boş veya 0 veya yanlış yazan bir belge.

Benzer şekilde, parolaları değiştirmek veya ayarlamak için sadece ' PUTe gidin /api/users/1/password.

(Kredi gibi) bir şey eklemeniz gerektiğinde, POSTs cinsinden düşünün . Örneğin, eklenecek kredilerin sayısını içeren bir gövdeye POSTbenzer bir kaynağa a yapabilirsiniz /api/users/1/credits. PUTAynı kaynaktaki A , değerin üzerine yazmak yerine değerin üzerine yazmak için kullanılabilir. POSTVücutta negatif bir sayı olan A çıkarılır, vb.

3. Temel HTTP durum kodlarını genişletmemenizi şiddetle tavsiye ederim. Durumunuza tam olarak uyan bir tane bulamazsanız, en yakın olanı seçin ve hata ayrıntılarını yanıt gövdesine yerleştirin. Ayrıca, HTTP başlıklarının genişletilebilir olduğunu unutmayın; uygulamanız istediğiniz tüm özel başlıkları tanımlayabilir. Örneğin üzerinde çalıştığım bir uygulama 404 Not Foundbirden fazla koşulda geri dönebilir . İstemciyi yanıt gövdesini ayrıştırmak yerine X-Status-Extended, özel durum kodu uzantılarımızı içeren yeni bir başlık ekledik . Yani şöyle bir yanıt görebilirsiniz:

HTTP/1.1 404 Not Found    
X-Status-Extended: 404.3 More Specific Error Here

Bu şekilde, bir web tarayıcısı gibi bir HTTP istemcisi normal 404 koduyla ne yapılacağını bilir ve daha sofistike bir HTTP istemcisi X-Status-Extendeddaha spesifik bilgiler için başlığa bakmayı seçebilir .

4. Kimlik doğrulama için mümkünse HTTP kimlik doğrulamasını kullanmanızı öneririm. Ancak IMHO, sizin için daha kolaysa çerez tabanlı kimlik doğrulamasını kullanmanın yanlış bir yanı yoktur.


4
Daha büyük bir kaynağın daha küçük kısımlarına bir şeyler yapmak için "genişletilmiş" kaynaklar kullanma konusunda düzgün bir fikir.
01'de womble

1
Çerezler HTTP / REST'te geçerlidir, ancak sunucu çerezi durum olarak kaydetmemelidir (bu nedenle oturum olarak değil). Çerez, HMAC gibi bir değeri depolayabilir, ancak bu durum başka bir yere bakmadan sökülebilir.
Bruce Alderson

14

REST Temel Bilgileri

REST, REST istemcisinin gerçek REST hizmetinin uygulamaya özgü ayrıntıları yerine standartlara güvenmesi gerektiğini belirten tek biçimli bir arabirim kısıtlamasına sahiptir, bu nedenle REST istemcisi küçük değişikliklerden kopmaz ve muhtemelen yeniden kullanılabilir.

Bu nedenle REST istemcisi ile REST hizmeti arasında bir sözleşme vardır. Temel protokol olarak HTTP kullanıyorsanız, aşağıdaki standartlar sözleşmenin bir parçasıdır:

  • HTTP 1.1
    • yöntem tanımları
    • durum kodu tanımları
    • önbellek kontrol başlıkları
    • kabul et ve içerik türü başlıkları
    • yetkilendirme başlıkları
  • IRI (utf8 URI )
  • gövde (birini seç)
  • köprüler
    • onları ne içermeli (birini seç)
      • bağlantı başlıklarını gönderme
      • html, atom + xml, hal + json, ld + json & hydra, vb. gibi bir hiper ortam yanıtı gönderme ...
    • semantik
      • IANA bağlantı ilişkilerini ve muhtemelen özel bağlantı ilişkilerini kullanma
      • uygulamaya özel RDF kelime haznesi kullanma

REST, REST hizmeti ile istemci arasındaki iletişimin vatansız olması gerektiğini bildiren vatansız bir kısıtlamaya sahiptir. Bu, REST hizmetinin istemci durumlarını koruyamayacağı anlamına gelir, bu nedenle sunucu tarafı oturum depolama alanınız olamaz. Her isteği doğrulamanız gerekiyor. Örneğin, HTTP temel kimlik doğrulaması (HTTP standardının bir parçası) uygundur, çünkü her istekte kullanıcı adını ve şifreyi gönderir.

Size soruları cevaplamak için

  1. Evet olabilir.

    Sadece belirtmek gerekirse, müşteriler IRI yapısını önemsemiyorlar, anlambilimleri önemsiyorlar, çünkü bağlantı ilişkileri veya bağlantılı veri (RDF) özniteliklerine sahip bağlantıları takip ediyorlar.

    IRI'lar hakkında önemli olan tek şey, tek bir IRI'nın yalnızca tek bir kaynağı tanımlaması gerektiğidir. Bir kullanıcı gibi tek bir kaynağın birçok farklı IRI'ye sahip olmasına izin verilir.

    Güzel IRI'ları neden kullanmamız oldukça basittir /users/123/password; IRI'yi basitçe okuyarak anladığınızda yönlendirme mantığını sunucuya yazmak çok daha kolaydır.

  2. PUT, PATCH, OPTIONS ve hatta daha fazlası gibi daha fazla filonuz var, ancak bunlardan daha fazlasına ihtiyacınız yok ... Yeni fiiller eklemek yerine yeni kaynakları nasıl ekleyeceğinizi öğrenmelisiniz.

    activate_login -> PUT /login/active true deactivate_login -> PUT /login/active false change_password -> PUT /user/xy/password "newpass" add_credit -> POST /credit/raise {details: {}}

    (Oturum açma durumu vatansız kısıtlama nedeniyle REST açısından anlamsızdır.)

  3. Kullanıcılarınız sorunun neden varolduğunu umursamıyor. Sadece başarı veya hata ve muhtemelen anlayabilecekleri bir hata mesajı olup olmadığını bilmek istiyorlar, örneğin: "Üzgünüz, ancak yazınızı kaydedemedik.", Vb ...

    HTTP durum başlıkları standart başlıklarınızdır. Diğer her şey bence vücutta olmalı. Tek bir başlık, örneğin ayrıntılı çok dilli hata mesajlarını tanımlamak için yeterli değildir.

  4. Durumsuz kısıtlama (önbellek ve katmanlı sistem kısıtlamaları ile birlikte), hizmetin iyi ölçeklenmesini sağlar. İstemcilerde aynısını yapabileceğinizde, sunucuda milyonlarca oturum sürdürmek istemezsiniz ...

    Kullanıcı ana istemciyi kullanarak ona erişim izni verirse, üçüncü taraf istemcisi bir erişim belirteci alır. Bundan sonra, 3. taraf istemci her istekle erişim kodunu gönderir. Daha karmaşık çözümler vardır, örneğin her bir isteği imzalayabilirsiniz, vb. Daha fazla ayrıntı için OAuth kılavuzuna bakın.

İlgili literatür


11

Belirttiğiniz örnekler için aşağıdakileri kullanacağım:

activate_login

POST /users/1/activation

deactivate_login

DELETE /users/1/activation

şifre değiştir

PUT /passwords (bu kullanıcının kimliğinin doğrulandığını varsayar)

kredi ekle

POST /credits (bu kullanıcının kimliğinin doğrulandığını varsayar)

Hatalar için, gövdede hatayı isteği aldığınız biçimde döndürürsünüz;

DELETE /users/1.xml

Yanıtı XML olarak geri gönderirsiniz, aynı durum JSON vb. İçin de geçerlidir.

Kimlik doğrulaması için http kimlik doğrulaması kullanmalısınız.


1
createURI'nin bir parçası olarak kullanmazdım (URI'lerin isimler olması gerektiğini ve HTTP yöntemlerinin bu isimler üzerinde çalışan fiiller olması gerektiğini unutmayın.) Bunun yerine, /users/1/activebasit bir boolean gibi bir kaynağım olurdu ve bu kaynağa 1 veya 0 koyarak.
friedo

Haklısın, / create'i çıkardım. Sadece singleton kaynağına bir gönderi olmalı.
jonnii

3
activationAçıkça bir kaynağı adıyla değiştirip yönetmezseniz, URI'de de kullanmazdım /users/1/activation. Bir GET ne işe yarar? PUT ne yapar? Bana URI'yi belirttiğinizi hissettiriyor. Ayrıca, içerik türü pazarlıklarında olduğu gibi, bu genellikle en iyi URI'den çıkarılır ve başlıklara eklenir Accept.
Cheeso

6
  1. Yeni kaynak URI'nin nasıl görüneceğini bilmediğinizde yazı kullanın (yeni kullanıcı oluşturursunuz, uygulama kimliğine yeni kullanıcıyı atar), nasıl temsil edileceğini bildiğiniz kaynakları güncellemek veya oluşturmak için PUT (örnek : PUT /myfiles/thisismynewfile.txt)
  2. ileti gövdesinde hata açıklamasını döndürme
  3. HTTP kimlik doğrulamasını kullanabilirsiniz (yeterliyse) Web hizmetleri stateler olmalıdır

5

(İlk geçiş olarak) PUTyalnızca mevcut varlıkları güncellemek için kullanılmasını öneririm . POSTyenilerini oluşturmak için kullanılmalıdır. yani

/api/users     when called with PUT, creates user record

bana doğru gelmiyor. Bununla birlikte, ilk bölümünüzün geri kalanı (fiil kullanımı) mantıklı görünür.


muhtemelen biri bunun gerçekten sorusuna bir cevap olmadığını düşündü
Lubos Hasko

6
Yeni varlıklar oluşturmak için POST'a karşı PUT almam, arayan kaynak adını kontrol ettiğinde PUT kullanmaktır, böylece callee yeni kaynak adını kontrol ettiğinde (buradaki örnekte olduğu gibi) tam kaynağa ve POST'ye PUT yapabilirsiniz.
SteveD

5

Ayrıntılı, ancak http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html adresindeki HTTP 1.1 yöntem belirtiminden kopyalandı

9.3 ALIN

GET yöntemi, İstek-URI'si tarafından tanımlanan herhangi bir bilgiyi (bir varlık şeklinde) almak anlamına gelir. İstek URI'sı bir veri üretme sürecine atıfta bulunursa, bu metin sürecin çıktısı olmadıkça, sürecin kaynak metni olarak değil yanıtta varlık olarak döndürülecek olan üretilen verilerdir.

İstek iletisi bir If-Modified-Since, If-Mododified-Since, If-Match, If-None-Match veya If-Range üstbilgisi alanını içeriyorsa, GET yönteminin anlam bilgisi "koşullu GET" olarak değişir. Koşullu bir GET yöntemi, kuruluşun yalnızca koşullu başlık alanları tarafından tanımlanan koşullar altında aktarılmasını ister. Koşullu GET yöntemi, önbelleğe alınan varlıkların birden fazla istek gerekmeden veya istemci tarafından zaten tutulan verileri aktarmadan yenilenmesine izin vererek gereksiz ağ kullanımını azaltmayı amaçlamaktadır.

İstek iletisi bir Aralık üstbilgisi alanı içeriyorsa, GET yönteminin anlam bilgisi "kısmi GET" olarak değişir. Kısmi bir GET, bölüm 14.35'te açıklandığı gibi, işletmenin sadece bir kısmının aktarılmasını talep eder. Kısmi GET yönteminin, kısmen alınan varlıkların zaten istemci tarafından tutulan veriler aktarılmadan tamamlanmasına izin vererek gereksiz ağ kullanımını azaltması amaçlanmıştır.

Bir GET isteğine yanıt, yalnızca ve yalnızca bölüm 13'te açıklanan HTTP önbelleğe alma gereksinimlerini karşılıyorsa önbelleğe alınabilir.

Formlar için kullanıldığında güvenlikle ilgili konular için bkz. Bölüm 15.1.3.

9.5 SONRASI

POST yöntemi, kaynak sunucunun, istekte yer alan varlığı İstek Satırında İstek-URI'si tarafından tanımlanan kaynağın yeni bir alt öğesi olarak kabul etmesini istemek için kullanılır. POST, aşağıdaki işlevleri kapsaması için tek tip bir yönteme izin verecek şekilde tasarlanmıştır:

  - Annotation of existing resources;
  - Posting a message to a bulletin board, newsgroup, mailing list,
    or similar group of articles;
  - Providing a block of data, such as the result of submitting a
    form, to a data-handling process;
  - Extending a database through an append operation.

POST yöntemi tarafından gerçekleştirilen gerçek işlev sunucu tarafından belirlenir ve genellikle İstek URI'sına bağlıdır. Gönderilen varlık, bir dosyanın kendisini içeren bir dizine tabi olduğu şekilde bu URI'ye bağlıdır, bir haber makalesi gönderildiği bir haber grubuna veya bir kayıt bir veritabanına bağlıdır.

POST yöntemi tarafından gerçekleştirilen eylem, bir URI tarafından tanımlanabilecek bir kaynakla sonuçlanmayabilir. Bu durumda, yanıtın sonucu tanımlayan bir varlık içerip içermediğine bağlı olarak 200 (Tamam) veya 204 (İçerik Yok) uygun yanıt durumudur.

Kaynak sunucuda bir kaynak oluşturulduysa, yanıt 201 (Oluşturuldu) olmalı ve isteğin durumunu açıklayan ve yeni kaynağa ve bir Konum başlığına başvuran bir varlık içermelidir (bkz. Bölüm 14.30).

Yanıt uygun Önbellek Denetimi veya Süresi Sonu başlık alanlarını içermediği sürece bu yönteme verilen yanıtlar önbelleğe alınamaz. Ancak, 303 (Diğerine Bak) yanıtı, kullanıcı aracısını önbelleğe alınabilir bir kaynağı almaya yönlendirmek için kullanılabilir.

POST istekleri bölüm 8.2'de belirtilen mesaj iletim gereksinimlerine uymalıdır * ZORUNLU *.

Güvenlikle ilgili konular için bkz. Bölüm 15.1.3.

9.6 PUT

PUT yöntemi, ekteki varlığın sağlanan Request-URI altında saklanmasını ister. İstek URI'si zaten var olan bir kaynağa başvuruyorsa, ekteki varlık, kaynak sunucuda bulunanın değiştirilmiş bir sürümü olarak düşünülmelidir. İstek URI'sı varolan bir kaynağı göstermiyorsa ve bu URI, istekte bulunan kullanıcı aracısı tarafından yeni bir kaynak olarak tanımlanabiliyorsa, kaynak sunucu bu URI ile kaynağı oluşturabilir. Yeni bir kaynak oluşturulursa, kaynak sunucu 201 (Oluşturuldu) yanıtı aracılığıyla kullanıcı aracısını bilgilendirmelidir ZORUNLU. Mevcut bir kaynak değiştirilirse, isteğin başarılı bir şekilde tamamlandığını göstermek için 200 (Tamam) veya 204 (İçerik Yok) yanıt kodu gönderilmelidir. Kaynak Request-URI ile oluşturulamadı veya değiştirilemediyse, sorunun doğasını yansıtan uygun bir hata yanıtı verilmelidir. Varlığın alıcısı, anlamadığı veya uygulamadığı herhangi bir Content- * (örn. Content-Range) başlığını göz ardı ETMEMELİDİR ve bu gibi durumlarda 501 (Uygulanmadı) yanıtı döndürmelidir ZORUNLU.

İstek bir önbellekten geçerse ve İstek URI'sı şu anda önbelleğe alınmış bir veya daha fazla varlığı tanımlarsa, bu girdilere eski olarak davranılmalıdır. Bu yönteme verilen yanıtlar önbelleğe alınamaz.

POST ve PUT istekleri arasındaki temel fark, İstek-URI'sinin farklı anlamına yansır. Bir POST isteğindeki URI, ekteki varlığı işleyecek kaynağı tanımlar. Bu kaynak veri kabul eden bir süreç, başka bir protokole açılan bir geçit veya ek açıklamaları kabul eden ayrı bir varlık olabilir. Buna karşılık, bir PUT isteğindeki URI, istekle birlikte gelen varlığı tanımlar - kullanıcı aracısı, URI'nin ne olduğunu bilir ve sunucunun, isteği başka bir kaynağa uygulamaması GEREKİR. Sunucu, isteğin farklı bir URI'ye uygulanmasını istiyorsa,

301 (Kalıcı Olarak Taşındı) yanıtı göndermelidir ZORUNLU; kullanıcı aracısı daha sonra isteği yeniden yönlendirip yönlendirmemeye ilişkin kendi kararını verebilir.

Tek bir kaynak birçok farklı URI tarafından tanımlanabilir. Örneğin, bir makalede "geçerli sürümü" tanımlamak için bir URI olabilir ve bu da her bir sürümü tanımlayan URI'den ayrı olabilir. Bu durumda, genel bir URI üzerindeki bir PUT isteği, kaynak sunucu tarafından diğer birkaç URI'nin tanımlanmasına neden olabilir.

HTTP / 1.1, bir PUT yönteminin bir kaynak sunucunun durumunu nasıl etkilediğini tanımlamaz.

PUT istekleri, bölüm 8.2'de belirtilen mesaj iletim gereksinimlerine uymak ZORUNLUDUR.

Belirli bir varlık başlığı için aksi belirtilmedikçe, PUT isteğindeki varlık başlıkları, PUT tarafından oluşturulan veya değiştirilen kaynağa uygulanmalıdır.

9.7 SİL

DELETE yöntemi, kaynak sunucunun Request-URI tarafından tanımlanan kaynağı silmesini ister. Bu yöntem, kaynak sunucuya insan müdahalesi (veya başka yollarla) geçersiz kılınabilir. Kaynak sunucudan döndürülen durum kodu, eylemin başarıyla tamamlandığını gösterse bile, istemcinin işlemin gerçekleştirildiği garanti edilemez. Ancak, yanıt verildiği sırada kaynağı silmeyi veya erişilemeyen bir konuma taşıma niyetinde olmadığı sürece sunucu başarıyı GÖSTERMEMELİDİR.

Yanıt, durumu tanımlayan bir varlık içeriyorsa başarılı bir yanıt 200 (Tamam), eylem henüz yürürlüğe girmemişse 202 (Kabul edildi) veya eylem yürürlüğe girmiş ancak yanıt içermiyorsa 204 (İçerik Yok) olmalıdır bir varlık.

İstek bir önbellekten geçerse ve İstek URI'sı şu anda önbelleğe alınmış bir veya daha fazla varlığı tanımlarsa, bu girdilere eski olarak davranılmalıdır. Bu yönteme verilen yanıtlar önbelleğe alınamaz.


2

REST dönüş kodları hakkında: HTTP protokol kodlarını ve REST sonuçlarını karıştırmak yanlıştır .

Bununla birlikte, onları karıştıran birçok uygulama gördüm ve birçok geliştirici benimle aynı fikirde olmayabilir.

HTTP dönüş kodları HTTP Requestkendisiyle ilgilidir. Bir REST çağrısı, Köprü Metni Aktarım Protokolü isteği kullanılarak yapılır ve çağrılan REST yönteminin kendisinden daha düşük bir düzeyde çalışır. REST bir kavram / yaklaşımdır ve çıktısı bir iş / mantıksal sonucudur, HTTP sonuç kodu ise bir aktarımdır .

Örneğin, / users / komutunu çağırdığınızda "404 Bulunamadı" ifadesinin döndürülmesi karıştırılabilir, çünkü bu şu anlama gelebilir:

  • URI yanlış (HTTP)
  • Kullanıcı bulunamadı (REST)

"403 Yasak / Erişim Reddedildi":

  • Özel izin gerekiyor. Tarayıcılar kullanıcı / parola sorarak bunu kaldırabilir. (HTTP)
  • Sunucuda yanlış erişim izinleri yapılandırılmış. (HTTP)
  • Kimlik doğrulamanız gerekiyor (REST)

Ve liste '500 Sunucu hatası' (Apache / Nginx HTTP atılan hatası veya REST'te iş kısıtlaması hatası) veya diğer HTTP hataları vb. İle devam edebilir.

Koddan, hata nedeninin, HTTP (taşıma) hatasının veya REST (mantıksal) hatasının ne olduğunu anlamak zordur.

HTTP isteği fiziksel olarak başarıyla gerçekleştirilmişse , bulunan kayıt (lar) ne olursa olsun, her zaman 200 kod döndürmelidir. Çünkü URI kaynağı bulundu ve http sunucusu tarafından işlendi. Evet, boş bir set döndürebilir. Http sonucu 200 olan boş bir web sayfası almak mümkün müdür, değil mi?

Bunun yerine 200 HTTP kodu ve sadece boş bir dizi / nesne içeren bir JSON döndürebilir veya gerçekleştirilen işlem durumu hakkında bilgi vermek için bir bool sonucu / başarı bayrağı kullanabilirsiniz.

Ayrıca, bazı internet sağlayıcıları isteklerinizi kesebilir ve size bir 404 http kodu döndürebilir. Bu, verilerinizin bulunmadığı anlamına gelmez, ancak taşıma düzeyinde yanlış bir şeydir.

Gönderen Wiki :

Temmuz 2004'te, Birleşik Krallık telekom sağlayıcısı BT Grubu, Internet Watch Foundation tarafından potansiyel olarak yasadışı olduğu belirlenen içerik taleplerine 404 hatası veren Cleanfeed içerik engelleme sistemini kurdu. Diğer ISS'ler aynı durumlarda bir HTTP 403 "yasak" hatası döndürür. Tayland ve Tunus'ta sansürü gizleme aracı olarak sahte 404 hatalarının kullanıldığı da bildirildi. 2011 devriminden önce sansürün ağır olduğu Tunus'ta, insanlar sahte 404 hatalarının doğasının farkına vardı ve "görünmez sansürü" temsil eden "Ammar 404" adlı hayali bir karakter yarattı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.