若你曾寫過 REST API,你確定體驗過那些無休止的爭論,例如該使用哪一個動詞?該使用哪一個 HTTP 狀態碼?該如何組織個人 URL?這些都沒有正確答案。不是全部的操做都能由某個動詞表示。不是全部的錯誤都匹配 HTTP 錯誤。爲什麼咱們要在 API 上使用那些爲超文本設計的動詞和錯誤碼?咱們使用 HTTP 做爲客戶端/服務端的通訊方式是由於它是如此廣泛,在它上面增長 REST 多是殺雞用牛刀了,特別當你只是想要一個簡單的 API 接口。web
思考這個典型的 API 在其餘語言中的調用以及它是如何轉化爲 REST。數據庫
OrderDTO Customer::GetOrder(int customerID, int orderID)
做爲一個 REST 調用應該相似這樣編程
GET /customer/33245/order/8769
若是咱們將方法名置於變量之間,那麼問題就來了,該 URL 的哪部分是終點?哪些是參數?這些參數又與什麼對應?很難僅僅經過 URL 推斷出它是如何傳遞給後端的。後端
一個簡單的 API,與咱們原始的方法調用很像,沒有混淆參數名稱,而且清晰定義了要傳遞的參數數組
GET /customer/getOrder?customerID=33245&orderID=8769
做爲一位 API 用戶或是設計師,上面的 URL 更容易被理解,由於方法調用和參數被清晰的分離開來。這並非 RESTful,可是除此以外在編程中哪裏還用過如此相似 REST 的模式?有語言強制要求使用 4 個動詞來修飾嗎?這些真的必要嗎?簡單的說,這不是必要的。POST 解決一切。服務器
REST URL 看起來『更乾淨』,但它們更容易被理解嗎?SEO 不是必要的。當你但願擴展更多參數,或使用更加複雜的參數例如數組,這些『簡單』的 URL 會讓你很頭疼。app
GET /customer/33245/order/8769
爲什麼不把參數從 URL 中移除?將它們放在 query string,或以 JSON 格式 POST 過去。這樣子參數被顯示命名,更易理解,消除了對複雜路由屬性的依賴。post
POST /customer/getOrder { customerID: 33245, orderID: 8769 }
爲什麼要用爲接收超文本而設計的數量有限的錯誤碼來表示你的錯誤響應?測試
保存來自服務器自身錯誤的 HTTP 特定錯誤碼。例如你獲得一個 404 響應,那麼它來自服務器仍是你的應用程序?一個簡化的 API 可能在成功時返回 HTTP 200 ,在遇到錯誤時返回 500 和應用級錯誤碼。設計
這些代碼能夠是爲業務定製的(訂單未找到,攝像頭未找到,數據庫跪了,已打包等等)。代碼能夠是惟一以方便追溯。測試中結合特定應用錯誤碼能夠提升測試準確性。
POST /shipment/cancel { orderID: 567, reason: ‘Wrong size’ } 400 Response { appError: 1023, message: ‘Order already shipped’, showUser: true }
若是你以爲 HTTP 響應應該是 500 而不是 400,那麼這只是這篇文章的部分觀點。關於怎麼作是『對』的爭論一直存在。
REST 和 RESTful 之間的一個核心區別在於 HATEOAS 的實現。通常是在你的 API 請求響應中發送相關 API 的 URL。若是你的 API 以一個銀行的存款響應了,它也包含用來取錢的 URL。這種方式下 API 是可發現和可遍歷的。在其餘語言中 API 調用不返回方法指針指向相關的方法。因此又一次發問,爲什麼咱們將 API 搞得如此複雜?僅僅由於咱們咱們經過 HTTP 來執行它們仍是爲了適應別人的學說?
另外一個常常實現不少魔法的地方就是 API 版本控制方案。若是一個單一方法須要版本控制那麼它能夠簡單的以 /user/getProfile2
形式實現,爲什麼要用其餘不直接的方法?若是控制器入口須要控制版本,能夠簡單的相似於 /user2/getProfile
。難道須要任何更復雜的東西嗎?沒有特殊的路由,沒有魔法而且直接映射到你的後端控制器和方法。
一個 URL 應該清晰定義了位置,終點和參數。無需複雜的路由代碼來分離參數。或是經過動詞區分意圖。
動詞無關性,HTTP 動詞真的只應該用來識別參數的去向 - 對 GET 來講它在 query string,對於 POST 它在 body。
版本控制應具體到被修改的事物。向下兼容易於維護,無需特殊的映射或屬性。
HTTP 錯誤碼,簡化爲 200/400。response body 包含應用特定錯誤碼和消息。
具象狀態傳輸,例如
GET /user/getProfile
可能返回一個 ProfileDTO (具象狀態) 能被更新和做爲一個參數經過下面的 API 回傳至服務器
POST /user/setProfile
沒有人在正確的 URL,動詞或狀態碼上達成一致意見。REST 是一種風格,而不是一種標準。在遠程 web 服務器上調用方法應該是一個簡單的 RPC。 方法名稱不和參數混合。方法不用動詞修飾。參數都在一個單獨的地方。簡單。
原文:who-cares-about-get-vs-post-norest by swax
做者:swax