本文轉載自:衆成翻譯 譯者:SlaneYang 連接:http://www.zcfy.cc/article/4388 原文:https://blog.philipphauer.de/restful-api-design-best-practicesjava
原文:RESTful API Design. Best Practices in a Nutshell.
做者:Philipp Hauershell
項目資源的URL應該如何設計?用名詞複數仍是用名詞單數?一個資源須要多少個URL?用哪一種HTTP方法來建立一個新的資源?可選參數應該放在哪裏?那些不涉及資源操做的URL呢?實現分頁和版本控制的最好方法是什麼?由於有太多的疑問,設計RESTful API變得很棘手。在這篇文章中,咱們來看一下RESTful API設計,並給出一個最佳實踐方案。數據庫
資源集合用一個URL,具體某個資源用一個URL:api
/employees #資源集合的URL /employees/56 #具體某個資源的URL
這讓你的API更簡潔,URL數目更少。不要這麼設計:緩存
/getAllEmployees /getAllExternalEmployees /createEmployee /updateEmployee
更好的設計:服務器
GET /employees GET /employees?state=external POST /employees PUT /employees/56
使用URL指定你要用的資源。使用HTTP方法來指定怎麼處理這個資源。使用四種HTTP方法POST,GET,PUT,DELETE能夠提供CRUD功能(建立,獲取,更新,刪除)。restful
2個URL乘以4個HTTP方法就是一組很好的功能。看看這個表格:dom
<table> <thead> <th></th> <th>POST(建立)</th> <th>GET(讀取)</th> <th>PUT(更新)</th> <th>DELETE(刪除)</th> </thead> <tbody> <tr> <td>/employees</td> <td>建立一個新員工</td> <td>列出全部員工</td> <td>批量更新員工信息</td> <td>刪除全部員工</td> </tr> <tr> <td>/employees/56</td> <td>(錯誤)</td> <td>獲取56號員工的信息</td> <td>更新56號員工的信息</td> <td>刪除56號員工</td> </tr> </tbody> </table>測試
建立一個新資源的時,客戶端與服務器是怎麼交互的呢? 翻譯
<center>在資源集合URL上使用POST來建立新的資源過程</center>
/employees
發送POST請求。HTTP body 包含新資源的屬性 「Albert Stark」。<center>使用PUT更新已有資源。</center> 1. 客戶端向具體資源的URL發送PUT請求`/employee/21`。請求的HTTP body中包含要更新的屬性值(21號員工的新名稱「Bruce Wayne」)。 2. REST服務器更新ID爲21的員工名稱,並使用HTTP狀態碼200表示更改爲功。
推薦:
/employees /employees/21
不推薦:
/employee /employee/21
事實上,這是我的愛好問題,但複數形式更爲常見。此外,在資源集合URL上用GET方法,它更直觀,特別是GET /employees?state=external
、POST /employees
、PUT /employees/56
。但最重要的是:避免複數和單數名詞混合使用,這顯得很是混亂且容易出錯。
不推薦作法:
GET /employees GET /externalEmployees GET /internalEmployees GET /internalAndSeniorEmployees
爲了讓你的URL更小、更簡潔。爲資源設置一個基本URL,將可選的、複雜的參數用查詢字符串表示。
GET /employees?state=internal&maturity=senior
RESTful Web服務應使用合適的HTTP狀態碼來響應客戶端請求
<table> <thead> <th>2xx:成功</th> <th>3xx:重定向</th> <th>4xx:客戶端錯誤</th> <th>5xx:服務器錯誤</th> </thead> <tbody> <tr> <td>200 成功</td> <td>301 永久重定向</td> <td>400 錯誤請求</td> <td>500 內部服務器錯誤</td> </tr> <tr> <td>201 建立</td> <td>304 資源未修改</td> <td>401未受權</td> <td></td> </tr> <tr> <td></td> <td></td> <td>403 禁止</td> <td></td> </tr> <tr> <td></td> <td></td> <td>404 未找到</td> <td></td> </tr> </tbody> </table>
除了合適的狀態碼以外,還應該在HTTP響應正文中提供有用的錯誤提示和詳細的描述。這是一個例子。 請求:
GET /employees?state=super
響應:
// 400 Bad Request { "message": "You submitted an invalid state. Valid state values are 'internal' or 'external'", "errorCode": 352, "additionalInformation" : "http://www.domain.com/rest/errorcode/352" }
使用小駝峯命名法做爲屬性標識符。
{ "yearOfBirth": 1982 }
不要使用下劃線(year_of_birth
)或大駝峯命名法(YearOfBirth
)。一般,RESTful Web服務將被JavaScript編寫的客戶端使用。客戶端會將JSON響應轉換爲JavaScript對象(經過調用var person = JSON.parse(response)
),而後調用其屬性。所以,最好遵循JavaScript代碼通用規範。
對比:
person.year_of_birth // 不推薦,違反JavaScript代碼通用規範 person.YearOfBirth // 不推薦,JavaScript構造方法命名 person.yearOfBirth // 推薦
從始至終,都使用版本號發佈您的RESTful API。將版本號放在URL中以是必需的。若是您有不兼容和破壞性的更改,版本號將讓你能更容易的發佈API。發佈新API時,只需在增長版本號中的數字。這樣的話,客戶端能夠自如的遷移到新API,不會因調用徹底不一樣的新API而陷入困境。
使用直觀的 「v」 前綴來表示後面的數字是版本號。
/v1/employees
你不須要使用次級版本號(「v1.2」),由於你不該該頻繁的去發佈API版本。
一次性返回數據庫全部資源不是一個好主意。所以,須要提供分頁機制。一般使用數據庫中衆所周知的參數offset和limit。
/employees?offset=30&limit=15 #返回30 到 45的員工
若是客戶端沒有傳這些參數,則應使用默認值。一般默認值是offset = 0
和limit = 10
。若是數據庫檢索很慢,應當減少limit
值。
/employees #返回0 到 10的員工
此外,若是您使用分頁,客戶端須要知道資源總數。例: 請求:
GET /employees
響應:
{ "offset": 0, "limit": 10, "total": 3465, "employees": [ //... ] }
有時API調用並不涉及資源(如計算,翻譯或轉換)。例:
GET /translate?from=de_DE&to=en_US&text=Hallo GET /calculate?para2=23¶2=432
在這種狀況下,API響應不會返回任何資源。而是執行一個操做並將結果返回給客戶端。所以,您應該在URL中使用動詞而不是名詞,來清楚的區分資源請求和非資源請求。
提供對特定資源的搜索很容易。只需使用相應的資源集合URL,並將搜索字符串附加到查詢參數中便可。
GET /employees?query=Paul
若是要對全部資源提供全局搜索,則須要用其餘方法。前文提到,對於非資源請求URL,使用動詞而不是名詞。所以,您的搜索網址可能以下所示:
GET /search?query=Paul //返回 employees, customers, suppliers 等等.
理想狀況下,不會讓客戶端本身構造使用REST API的URL。讓咱們思考一個例子。 客戶端想要訪問員工的薪酬表。爲此,他必須知道他能夠經過在員工URL(例如/employees/21/salaryStatements
)中附加字符串「salaryStatements」來訪問薪酬表。這個字符串鏈接很容易出錯,且難以維護。若是你更改了訪問薪水錶的REST API的方式(例如變成了/employees/21/salary-statement
或/employees/21/paySlips
),全部客戶端都將中斷。 更好的方案是在響應參數中添加一個links
字段,讓客戶端能夠自動變動。
請求:
GET /employees/
響應:
//... { "id":1, "name":"Paul", "links": [ { "rel": "salary", "href": "/employees/1/salaryStatements" } ] }, //...
若是客戶端徹底依靠links
中的字段得到薪資表,你更改了API,客戶端將始終得到一個有效的URL(只要你更改了link
字段,請求的URL會自動更改),不會中斷。另外一個好處是,你的API變得能夠自我描述,須要寫的文檔更少。
在分頁時,您還能夠添加獲取下一頁或上一頁的連接示例。只需提供適當的偏移和限制的連接示例。
GET /employees?offset=20&limit=10
{ "offset": 20, "limit": 10, "total": 3465, "employees": [ //... ], "links": [ { "rel": "nextPage", "href": "/employees?offset=30&limit=10" }, { "rel": "previousPage", "href": "/employees?offset=10&limit=10" } ] }