2013-03-24 93 views
9

在RESTful API中返回HTTP狀態代碼的最佳做法是什麼?我爲我的PHP框架使用Laravel 4。RESTful API中的錯誤最佳實踐

在出現錯誤的情況下,應該使用

return Response::json('User Exists', 401); 

包括標誌success

return Response::json([ 
    'success' => false, 
    'data' => 'User Exists'], 
    401 
); 

使用200而不是4XX,依靠success,以確定是否有錯誤

return Response::json([ 
    'success' => false, 
    'data' => 'User Exists'], 
    200 
); 

而在成功的情況下,也沒有必要返回任何數據,你還回什麼?

PHP API代碼

public function getCheckUniqueEmail() { 
    // Check if Email already exist in table 'users' 
    $uniqueEmail = checkIfEmailExists(); 

    // Return JSON Response 
    if($uniqueEmail) { 
     // Validation fail (user exists) 
     return Response::json('User Exists', 401); 
    } else { 
     // Validation success 
     // - Return anything? 
    } 
} 

回答

12

當你看list of available HTTP status codes,你會在某個時刻認識到,有很多人,但單獨使用本身也不能真正解釋錯誤。

所以要回答你的問題,有兩個部分。一個是:你的API如何傳達錯誤的原因,並添加API的用戶(大多數情況下是另一個開發人員)可以閱讀和採取行動的有用信息。您應該儘可能多地添加機器可讀和人類可讀的信息。

另一部分:HTTP狀態代碼如何幫助區分某些錯誤(和成功)狀態?

這後一部分實際上比一件事情更難。有404個明顯的情況用於告訴「未找到」。而500是服務器端的任何錯誤。

我不會使用狀態401,除非我真的想讓操作在存在HTTP身份驗證憑證的情況下成功。 401通常會在瀏覽器中觸發一個對話框,這很糟糕。

如果資源是唯一且已存在的,狀態「409 Conflict」似乎是合適的。如果創建用戶成功,狀態「201 Created」聽起來也是一個好主意。

請注意,還有更多的狀態代碼,其中一些與HTTP協議的擴展(如DAV)有關,一些完全沒有標準化(例如狀態「420讓你的冷靜」從Twitter API中獲益)。看看http://en.wikipedia.org/wiki/List_of_HTTP_status_codes看看到目前爲止使用了什麼,然後決定是否要使用適合您的錯誤情況的東西。

根據我的經驗,簡單地選擇一個狀態碼並使用它是很容易的,但很難一致地按照現有標準進行操作。

我不會因爲別人會抱怨而停下來。 :)正確的做RESTful接口本身就是一項艱鉅的任務,但接口越多,獲得的經驗就越多。

編輯:

關於版本的:它被認爲是不好的做法,把一個版本標記到URL,像這樣:example.com/api/v1/stuff它會工作,但它是不是很好。

但首先是:您的客戶如何指定他想要獲得哪種表示形式,即他如何決定要麼獲取JSON或XML?答案:Accept標題。他可以爲JSON發送Accept: application/json,爲XML發送Accept: application/xml。他甚至可能接受多種類型,並且服務器決定返回什麼。

除非服務器被設計爲回答多個資源表示(JSON或XML,客戶端選擇),否則客戶端的確沒有多少選擇。但讓客戶至少發送「application/json」作爲他的唯一選擇,然後返回標題Content-type: application/json作爲迴應,這仍然是件好事。這樣,雙方都明確表示他們希望對方看到內容。

現在的版本。如果將版本放入URL中,則可以有效地創建不同的資源(v1和v2),但實際上,只有一個資源(= URL)使用不同的方法來訪問它。當請求的參數和/或與當前版本不兼容的響應中的表示發生突變時,必須創建API的新版本。

因此,當您創建使用JSON的API時,您不會處理泛型JSON。你處理一個具體的JSON結構,它對你的API來說是獨一無二的。您可以也可能應該在服務器發送的Content-type中指出這一點。 「供應商」的擴展是這樣的:Content-type: application/vnd.IAMVENDOR.MYAPI+json會告訴世界,基本的數據結構是application/json,但它是你的公司和你的API,真正地告訴哪個結構期望。而這正是API請求的版本適合的地方:application/vnd.IAMVENDOR.MYAPI-v1+json

因此,不要將版本放入URL中,而是期望客戶端發送Accept: application/vnd.IAMVENDOR.MYAPI-v1+json標題,並且您也以Content-type: application/vnd.IAMVENDOR.MYAPI-v1+json作爲響應。這對第一個版本確實沒有什麼影響,但讓我們看看版本2發揮作用時的情況。

URL方法將創建一組完全不相關的新資源。客戶端會懷疑example.com/api/v2/stuffexample.com/api/v1/stuff的資源是否相同。客戶端可能已經使用v1 API創建了一些資源,並且存儲了這些東西的URL。他應該如何將所有這些資源升級到v2?資源真的沒有改變,它們是一樣的,唯一改變的是它們在v2中看起來不同。

是的,服務器可能會通過發送重定向到v2 URL來通知客戶端。但重定向並不表示客戶端還必須升級API的客戶端部分。

對版本使用accept標頭時,資源的URL對於所有版本都是相同的。客戶端決定使用版本1或2請求資源,服務器可能如此友善,仍然可以回答版本1請求的版本1響應,但所有版本2的請求都帶有新的閃亮的版本2響應。

如果服務器無法應對版本1請求,他可以通過發送HTTP狀態「406不可接受」來告訴客戶端(請求的資源只能根據發送的接受頭文件生成不可接受的內容請求。)

客戶端可以發送包含兩個版本的accept頭,這使得服務器可以使用他最喜歡的版本進行響應,即智能客戶端可以實現版本1和版本2,並且現在將兩者都作爲accept頭髮送,並等待以便服務器從版本1升級到2.服務器會在每個響應中告訴它是版本1還是版本2,並且客戶端可以採取相應措施 - 他不需要知道服務器版本升級的確切日期。

總結一下:對於一個非常基本的API,即使有一個版本也許是有限的,可能是內部的,但是使用起來可能會過度。但是你永遠不知道這一年是否會成爲現實。將版本號包含到API中始終是一個非常好的主意。最好的地方在於您的API即將使用的mime類型。檢查單個現有版本應該是微不足道的,但您可以選擇稍後進行透明升級,而不會混淆現有客戶端。

+0

restful api只是爲我自己的網站的ajax/backbonejs/jquery使用。在這種情況下,我應該堅持相同的錯誤代碼(比如400)嗎?或者爲每個AJAX響應返回200,並檢查'success'變量以查看是否發生錯誤 – Nyxynyx 2013-03-24 15:50:03

+1

不,通過錯誤代碼指示基本的「成功/錯誤」事實是一個非常好的主意。錯誤響應由HTTP客戶端處理,例如,它們不應該被緩存等。在數據有效載荷內指示相同也是一件好事。我自己的API在成功時有「數據」,或者在失敗時有「錯誤」。這與「成功=真/假」基本相同,並且適用於我。但是確實知道狀態「400錯誤請求」不是您認爲的通用客戶端錯誤狀態。沒有這樣的事情,你必須指定錯誤狀態。 – Sven 2013-03-24 16:28:24

+2

很好的答案,斯文! 但是,您會說:>關於版本控制:將版本 >標記放入我不同意的網址中被認爲是不好的做法。這是Apigee的一個[指南](http://apigee.com/about/api-best-practices/restful-api-design-second-edition),他得出結論認爲* *確實是最佳的使用版本號的做法網址。他們還澄清了返回狀態代碼。 – unicopter 2013-04-10 19:27:14

2

我不會使用200狀態的一切。這隻會讓人困惑。

Jquery允許您以不同的方式處理不同的響應代碼,已經有內置的方法可以利用它們在您的應用程序中使用它們,當您的應用程序增長時,您可以提供該API供其他人使用。

編輯: 此外,我強烈建議看這個講Laravel和API開發:

http://kuzemchak.net/blog/entry/laracon-slides-and-video

+0

視頻鏈接很有幫助,但是演講者在實現RESTful API時會做一些不好的事情,比如在URL中包含版本號。這就是「接受」標題的用途。 – Sven 2013-03-24 16:49:03

+0

@Sven你能否詳細解釋一下如何使用它?我很好奇=) – msurguy 2013-03-24 21:29:27

+0

更新了我的答案。 – Sven 2013-03-25 00:32:32

1

有在Illuminate\Http\Response HTTP狀態代碼的一些列表擴展到Symfony\Component\HttpFoundation\Response。你可以在你的課堂上使用它。

例如:

use Illuminate\Http\Response as LaravelResponse; 
... 
return Response::json('User Exists', LaravelResponse::HTTP_CONFLICT); 

它更具有可讀性。