RESTful API設(shè)計(jì)最佳實(shí)踐
背景
目前互聯(lián)網(wǎng)上充斥著大量的關(guān)于RESTful API(為了方便,以后API和RESTful API 一個(gè)意思)如何設(shè)計(jì)的文章,然而卻沒(méi)有一個(gè)”萬(wàn)能“的設(shè)計(jì)標(biāo)準(zhǔn):如何鑒權(quán)?API格式如何?你的API是否應(yīng)該加入版本信息?當(dāng)你開(kāi)始寫(xiě)一個(gè)app的時(shí)候,特別是后端模型部分已經(jīng)寫(xiě)完的時(shí)候,你不得不殫精竭慮的設(shè)計(jì)和實(shí)現(xiàn)自己app的public API部分。因?yàn)橐坏┌l(fā)布,對(duì)外發(fā)布的API將會(huì)很難改變。
在給SupportedFu設(shè)計(jì)API的時(shí)候,我試圖以實(shí)用的角度來(lái)解決上面提到的問(wèn)題。我希望可以設(shè)計(jì)出容易使用,容易部署,并且足夠靈活的API,本文因此而生。
API設(shè)計(jì)的基本要求
網(wǎng)上的很多關(guān)于API設(shè)計(jì)的觀點(diǎn)都十分”學(xué)院派“,它們也許更有理論基礎(chǔ),但是有時(shí)卻和現(xiàn)實(shí)世界脫軌(因此我是自由派)。所以我這篇文章的目標(biāo)是從實(shí)踐的角度出發(fā),給出當(dāng)前網(wǎng)絡(luò)應(yīng)用的API設(shè)計(jì)最佳實(shí)踐(當(dāng)然,是我認(rèn)為的最佳了~),如果覺(jué)得不合適,我不會(huì)遵從標(biāo)準(zhǔn)。當(dāng)然作為設(shè)計(jì)的基礎(chǔ),幾個(gè)必須的原則還是要遵守的:
- 當(dāng)標(biāo)準(zhǔn)合理的時(shí)候遵守標(biāo)準(zhǔn)。
- API應(yīng)該對(duì)程序員友好,并且在瀏覽器地址欄容易輸入。
- API應(yīng)該簡(jiǎn)單,直觀,容易使用的同時(shí)優(yōu)雅。
- API應(yīng)該具有足夠的靈活性來(lái)支持上層ui。
- API設(shè)計(jì)權(quán)衡上述幾個(gè)原則。
需要強(qiáng)調(diào)的是:API的就是程序員的UI,和其他UI一樣,你必須仔細(xì)考慮它的用戶體驗(yàn)!
使用RESTful URLs 和action.
雖然前面我說(shuō)沒(méi)有一個(gè)萬(wàn)能的API設(shè)計(jì)標(biāo)準(zhǔn)。但確實(shí)有一個(gè)被普遍承認(rèn)和遵守:RESTfu設(shè)計(jì)原則。它被Roy Felding提出(在他的”基于網(wǎng)絡(luò)的軟件架構(gòu)“論文中第五章)。而REST的核心原則是將你的API拆分為邏輯上的資源。這些資源通過(guò)http被操作(GET ,POST,PUT,DELETE)。
那么我應(yīng)該如何拆分出這些資源呢?
顯然從API用戶的角度來(lái)看,”資源“應(yīng)該是個(gè)名詞。即使你的內(nèi)部數(shù)據(jù)模型和資源已經(jīng)有了很好的對(duì)應(yīng),API設(shè)計(jì)的時(shí)候你仍然不需要把它們一對(duì)一的都暴露出來(lái)。這里的關(guān)鍵是隱藏內(nèi)部資源,暴露必需的外部資源。
在SupportFu里,資源是 ticket、user、group。
一旦定義好了要暴露的資源,你可以定義資源上允許的操作,以及這些操作和你的API的對(duì)應(yīng)關(guān)系:
- GET /tickets # 獲取ticket列表
- GET /tickets/12 # 查看某個(gè)具體的ticket
- POST /tickets # 新建一個(gè)ticket
- PUT /tickets/12 # 更新ticket 12.
- DELETE /tickets/12 #刪除ticekt 12
可以看出使用REST的好處在于可以充分利用http的強(qiáng)大實(shí)現(xiàn)對(duì)資源的CURD功能。而這里你只需要一個(gè)endpoint:/tickets,再?zèng)]有其他什么命名規(guī)則和url規(guī)則了,cool!
這個(gè)endpoint的單數(shù)復(fù)數(shù)
一個(gè)可以遵從的規(guī)則是:雖然看起來(lái)使用復(fù)數(shù)來(lái)描述某一個(gè)資源實(shí)例看起來(lái)別扭,但是統(tǒng)一所有的endpoint,使用復(fù)數(shù)使得你的URL更加規(guī)整。這讓API使用者更加容易理解,對(duì)開(kāi)發(fā)者來(lái)說(shuō)也更容易實(shí)現(xiàn)。
如何處理關(guān)聯(lián)?關(guān)于如何處理資源之間的管理REST原則也有相關(guān)的描述:
- GET /tickets/12/messages- Retrieves list of messages for ticket #12
- GET /tickets/12/messages/5- Retrieves message #5 for ticket #12
- POST /tickets/12/messages- Creates a new message in ticket #12
- PUT /tickets/12/messages/5- Updates message #5 for ticket #12
- PATCH /tickets/12/messages/5- Partially updates message #5 for ticket #12
- DELETE /tickets/12/messages/5- Deletes message #5 for ticket #12
其中,如果這種關(guān)聯(lián)和資源獨(dú)立,那么我們可以在資源的輸出表示中保存相應(yīng)資源的endpoint。然后API的使用者就可以通過(guò)點(diǎn)擊鏈接找到相關(guān)的資源。如果關(guān)聯(lián)和資源聯(lián)系緊密。資源的輸出表示就應(yīng)該直接保存相應(yīng)資源信息。(例如這里如果message資源是獨(dú)立存在的,那么上面 GET /tickets/12/messages就會(huì)返回相應(yīng)message的鏈接;相反的如果message不獨(dú)立存在,他和ticket依附存在,則上面的 API調(diào)用返回直接返回message信息)
不符合CURD的操作
對(duì)這個(gè)令人困惑的問(wèn)題,下面是一些解決方法:
- 重構(gòu)你的行為action。當(dāng)你的行為不需要參數(shù)的時(shí)候,你可以把a(bǔ)ctive對(duì)應(yīng)到activated這個(gè)資源,(更新使用patch).
- 以子資源對(duì)待。例如:GitHub上,對(duì)一個(gè)gists加星操作:PUT /gists/:id/star 并且取消星操作:DELETE /gists/:id/star.
- 有時(shí)候action實(shí)在沒(méi)有難以和某個(gè)資源對(duì)應(yīng)上例如search。那就這么辦吧。我認(rèn)為API的使用者對(duì)于/search這種url也不會(huì)有太大意見(jiàn)的(畢竟他很容易理解)。只要注意在文檔中寫(xiě)清楚就可以了。
永遠(yuǎn)使用SSL
毫無(wú)例外,永遠(yuǎn)都要使用SSL。你的應(yīng)用不知道要被誰(shuí),以及什么情況訪問(wèn)。有些是安全的,有些不是。使用SSL可以減少鑒權(quán)的成本:你只需要一個(gè)簡(jiǎn)單的令牌(token)就可以鑒權(quán)了,而不是每次讓用戶對(duì)每次請(qǐng)求簽名。
值得注意的是:不要讓非SSL的url訪問(wèn)重定向到SSL的url。
文檔
文檔和API本身一樣重要。文檔應(yīng)該容易找到,并且公開(kāi)(把它們藏到pdf里面或者存到需要登錄的地方都不太好)。文檔應(yīng)該有展示請(qǐng)求和輸出的例子:或者以點(diǎn)擊鏈接的方式或者通過(guò)curl的方式(請(qǐng)見(jiàn)openstack的文檔)。如果有更新(特別是公開(kāi)的API),應(yīng)該及時(shí)更新文檔。文檔中應(yīng)該有關(guān)于何時(shí)棄用某個(gè)API的時(shí)間表以及詳情。使用郵件列表或者博客記錄是好方法。
版本化
在API上加入版本信息可以有效的防止用戶訪問(wèn)已經(jīng)更新了的API,同時(shí)也能讓不同主要版本之間平穩(wěn)過(guò)渡。關(guān)于是否將版本信息放入url還是放入請(qǐng)求頭有過(guò)爭(zhēng)論:API version should be included in the URL or in a header. 學(xué)術(shù)界說(shuō)它應(yīng)該放到header里面去,但是如果放到url里面我們就可以跨版本的訪問(wèn)資源了。。(參考o(jì)penstack)。
strip使用的方法就很好:它的url里面有主版本信息,同時(shí)請(qǐng)求頭倆面有子版本信息。這樣在子版本變化過(guò)程中url的穩(wěn)定的。變化有時(shí)是不可避免的,關(guān)鍵是如何管理變化。完整的文檔和合理的時(shí)間表都會(huì)使得API使用者使用的更加輕松。
結(jié)果過(guò)濾,排序,搜索:
url最好越簡(jiǎn)短越好,和結(jié)果過(guò)濾,排序,搜索相關(guān)的功能都應(yīng)該通過(guò)參數(shù)實(shí)現(xiàn)(并且也很容易實(shí)現(xiàn))。
過(guò)濾:為所有提供過(guò)濾功能的接口提供統(tǒng)一的參數(shù)。例如:你想限制get /tickets 的返回結(jié)果:只返回那些open狀態(tài)的ticket–get /tickektsstate=open這里的state就是過(guò)濾參數(shù)。
排序:和過(guò)濾一樣,一個(gè)好的排序參數(shù)應(yīng)該能夠描述排序規(guī)則,而不業(yè)務(wù)相關(guān)。復(fù)雜的排序規(guī)則應(yīng)該通過(guò)組合實(shí)現(xiàn):
- GET /ticketssort=-priority- Retrieves a list of tickets in descending order of priority
- GET /ticketssort=-priority,created_at- Retrieves a list of tickets in descending order of priority. Within a specific priority, older tickets are ordered first
這里第二條查詢中,排序規(guī)則有多個(gè)rule以逗號(hào)間隔組合而成。
搜索:有些時(shí)候簡(jiǎn)單的排序是不夠的。我們可以使用搜索技術(shù)(ElasticSearch和Lucene)來(lái)實(shí)現(xiàn)(依舊可以作為url的參數(shù))。
- GET /ticketsq=return&state=open&sort=-priority,created_at- Retrieve the highest priority open tickets mentioning the word ‘return’
對(duì)于經(jīng)常使用的搜索查詢,我們可以為他們?cè)O(shè)立別名,這樣會(huì)讓API更加優(yōu)雅。例如:
get /ticketsq=recently_closed -> get /tickets/recently_closed.
限制API返回值的域
有時(shí)候API使用者不需要所有的結(jié)果,在進(jìn)行橫向限制的時(shí)候(例如值返回API結(jié)果的前十項(xiàng))還應(yīng)該可以進(jìn)行縱向限制。并且這個(gè)功能能有效的提高網(wǎng)絡(luò)帶寬使用率和速度??梢允褂胒ields查詢參數(shù)來(lái)限制返回的域例如:
GET /ticketsfields=id,subject,customer_name,updated_at&state=open&sort=-updated_at
更新和創(chuàng)建操作應(yīng)該返回資源
PUT、POST、PATCH 操作在對(duì)資源進(jìn)行操作的時(shí)候常常有一些副作用:例如created_at,updated_at 時(shí)間戳。為了防止用戶多次的API調(diào)用(為了進(jìn)行此次的更新操作),我們應(yīng)該會(huì)返回更新的資源(updated representation.)例如:在POST操作以后,返回201 created 狀態(tài)碼,并且包含一個(gè)指向新資源的url作為返回頭
是否需要 “HATEOAS“
網(wǎng)上關(guān)于是否允許用戶創(chuàng)建新的url有很大的異議(注意不是創(chuàng)建資源產(chǎn)生的url)。為此REST制定了HATEOAS來(lái)描述了和endpoint進(jìn)行交互的時(shí)候,行為應(yīng)該在資源的metadata返回值里面進(jìn)行定義。
(譯注:作者這里認(rèn)為HATEOAS還不算成熟,我也不怎么理解這段就算了,讀者感興趣可以自己去原文查看)
只提供json作為返回格式
現(xiàn)在開(kāi)始比較一下XML和json了。XML即冗長(zhǎng),難以閱讀,又不適合各種編程語(yǔ)言解析。當(dāng)然XML有擴(kuò)展性的優(yōu)勢(shì),但是如果你只是將它來(lái)對(duì)內(nèi)部資源串行化,那么他的擴(kuò)展優(yōu)勢(shì)也發(fā)揮不出來(lái)。很多應(yīng)用(youtube,twitter,box)都已經(jīng)開(kāi)始拋棄XML了,我也不想多費(fèi)口舌。給了google上的趨勢(shì)圖吧:
當(dāng)然如果的你使用用戶里面企業(yè)用戶居多,那么可能需要支持XML。如果是這樣的話你還有另外一個(gè)問(wèn)題:你的http請(qǐng)求中的media類型是應(yīng)該和 accept 頭同步還是和url?為了方便(browser explorability),應(yīng)該是在url中(用戶只要自己拼url就好了)。如果這樣的話最好的方法是使用.xml或者.json的后綴。
命名方式?
是蛇形命令(下劃線和小寫(xiě))還是駝峰命名?如果使用json那么最好的應(yīng)該是遵守JAVASCRIPT的命名方法-也就是說(shuō)駱駝命名法。如果你正在使用多種語(yǔ)言寫(xiě)一個(gè)庫(kù),那么最好按照那些語(yǔ)言所推薦的,java,c#使用駱駝,python,ruby使用snake。
個(gè)人意見(jiàn):我總覺(jué)得蛇形命令更好使一些,當(dāng)然這沒(méi)有什么理論的依據(jù)。有人說(shuō)蛇形命名讀起來(lái)更快,能達(dá)到20%,也不知道真假http://ieeexplore.ieee.org/xpl/articleDetails.jsptp=&arnumber=5521745
默認(rèn)使用pretty print格式,使用gzip
只是使用空格的返回結(jié)果從瀏覽器上看總是覺(jué)得很惡心(一大坨有沒(méi)有?~)。當(dāng)然你可以提供url上的參數(shù)來(lái)控制使用“pretty print”,但是默認(rèn)開(kāi)啟這個(gè)選項(xiàng)還是更加友好。格外的傳輸上的損失不會(huì)太大。相反你如果忘了使用gzip那么傳輸效率將會(huì)大大減少,損失大大增加。想象一個(gè)用戶正在debug那么默認(rèn)的輸出就是可讀的-而不用將結(jié)果拷貝到其他什么軟件中在格式化-是想起來(lái)就很爽的事,不是么?
下面是一個(gè)例子:
$ curl https://API.github.com/users/veesahni > with-whitespace.txt $ ruby -r json -e 'puts JSON JSON.parse(STDIN.read)' < with-whitespace.txt > without-whitespace.txt $ gzip -c with-whitespace.txt > with-whitespace.txt.gz $ gzip -c without-whitespace.txt > without-whitespace.txt.gz
輸出如下:
- without-whitespace.txt- 1252 bytes
- with-whitespace.txt- 1369 bytes
- without-whitespace.txt.gz- 496 bytes
- with-whitespace.txt.gz- 509 bytes
在上面的例子中,多余的空格使得結(jié)果大小多出了8.5%(沒(méi)有使用gzip),相反只多出了2.6%。據(jù)說(shuō):twitter使用gzip之后它的 streaming API傳輸減少了80%(link:https://dev.twitter.com/blog/announcing-gzip- compression-streaming-APIs).
只在需要的時(shí)候使用“envelope”
很多API象下面這樣返回結(jié)果:
- {
- "data" : {
- "id" : 123,
- "name" : "John"
- }
- }
理由很簡(jiǎn)單:這樣做可以很容易擴(kuò)展返回結(jié)果,你可以加入一些分頁(yè)信息,一些數(shù)據(jù)的元信息等-這對(duì)于那些不容易訪問(wèn)到返回頭的API使用者來(lái)說(shuō)確實(shí)有用,但是隨著“標(biāo)準(zhǔn)”的發(fā)展(cors和http://tools.ietf.org/html/rfc5988#page-6都開(kāi)始被加入到標(biāo)準(zhǔn)中了),我個(gè)人推薦不要那么做。
何時(shí)使用envelope?
有兩種情況是應(yīng)該使用envelope的。如果API使用者確實(shí)無(wú)法訪問(wèn)返回頭,或者API需要支持交叉域請(qǐng)求(通過(guò)jsonp)。
jsonp請(qǐng)求在請(qǐng)求的url中包含了一個(gè)callback函數(shù)參數(shù)。如果給出了這個(gè)參數(shù),那么API應(yīng)該返回200,并且把真正的狀態(tài)碼放到返回值里面(包裝在信封里),例如:
- callback_function({
- status_code: 200,
- next_page: "https://..",
- response: {
- ... actual JSON response body ...
- }
- })
同樣為了支持無(wú)法方法返回頭的API使用者,可以允許envelope=true這樣的參數(shù)。
#p#
在post,put,patch上使用json作為輸入
如果你認(rèn)同我上面說(shuō)的,那么你應(yīng)該決定使用json作為所有的API輸出格式,那么我們接下來(lái)考慮考慮API的輸入數(shù)據(jù)格式。
很多的API使用url編碼格式:就像是url查詢參數(shù)的格式一樣:?jiǎn)渭兊逆I值對(duì)。這種方法簡(jiǎn)單有效,但是也有自己的問(wèn)題:它沒(méi)有數(shù)據(jù)類型的概念。這使得程序不得不根據(jù)字符串解析出布爾和整數(shù),而且還沒(méi)有層次結(jié)構(gòu)–雖然有一些關(guān)于層次結(jié)構(gòu)信息的約定存在可是和本身就支持層次結(jié)構(gòu)的json比較一下還是不很好用。
當(dāng)然如果API本身就很簡(jiǎn)單,那么使用url格式的輸入沒(méi)什么問(wèn)題。但對(duì)于復(fù)雜的API你應(yīng)該使用json。或者干脆統(tǒng)一使用json。
注意使用json傳輸?shù)臅r(shí)候,要求請(qǐng)求頭里面加入:Content-Type:applicatin/json.否則拋出415異常(unsupported media type)。
分頁(yè)
分頁(yè)數(shù)據(jù)可以放到“信封”里面,但隨著標(biāo)準(zhǔn)的改進(jìn),現(xiàn)在我推薦將分頁(yè)信息放到link header里面:http://tools.ietf.org/html/rfc5988#page-6。
使用link header的API應(yīng)該返回一系列組合好了的url而不是讓用戶自己再去拼。這點(diǎn)在基于游標(biāo)的分頁(yè)中尤為重要。例如下面,來(lái)自github的文檔
- Link: <https://api.github.com/user/repos?page=3&per_page=100>; rel="next",
- <https://api.github.com/user/repos?page=50&per_page=100>; rel="last"
自動(dòng)加載相關(guān)的資源
很多時(shí)候,自動(dòng)加載相關(guān)資源非常有用,可以很大的提高效率。但是這卻和RESTful的原則相背。為了如此,我們可以在url中添加參數(shù):embed(或者expend)。embed可以是一個(gè)逗號(hào)分隔的串,例如:
- GET /ticket/12embed=customer.name,assigned_user
對(duì)應(yīng)的API返回值如下:
- {
- "id" : 12,
- "subject" : "I have a question!",
- "summary" : "Hi, ....",
- "customer" : {
- "name" : "Bob"
- },
- assigned_user: {
- "id" : 42,
- "name" : "Jim",
- }
- }
值得提醒的是,這個(gè)功能有時(shí)候會(huì)很復(fù)雜,并且可能導(dǎo)致N+1 SELECT 問(wèn)題。
重寫(xiě)HTTP方法
有的客戶端只能發(fā)出簡(jiǎn)單的GET 和POST請(qǐng)求。為了照顧他們,我們可以重寫(xiě)HTTP請(qǐng)求。這里沒(méi)有什么標(biāo)準(zhǔn),但是一個(gè)普遍的方式是接受X-HTTP-Method-Override請(qǐng)求頭。
速度限制
為了避免請(qǐng)求泛濫,給API設(shè)置速度限制很重要。為此 RFC 6585 引入了HTTP狀態(tài)碼429(too many requests)。加入速度設(shè)置之后,應(yīng)該提示用戶,至于如何提示標(biāo)準(zhǔn)上沒(méi)有說(shuō)明,不過(guò)流行的方法是使用HTTP的返回頭。
下面是幾個(gè)必須的返回頭(依照twitter的命名規(guī)則):
- X-Rate-Limit-Limit :當(dāng)前時(shí)間段允許的并發(fā)請(qǐng)求數(shù)
- X-Rate-Limit-Remaining:當(dāng)前時(shí)間段保留的請(qǐng)求數(shù)。
- X-Rate-Limit-Reset:當(dāng)前時(shí)間段剩余秒數(shù)
為什么使用當(dāng)前時(shí)間段剩余秒數(shù)而不是時(shí)間戳?
時(shí)間戳保存的信息很多,但是也包含了很多不必要的信息,用戶只需要知道還剩幾秒就可以再發(fā)請(qǐng)求了這樣也避免了clock skew問(wèn)題。
有些API使用UNIX格式時(shí)間戳,我建議不要那么干。為什么?HTTP 已經(jīng)規(guī)定了使用 RFC 1123 時(shí)間格式
鑒權(quán) Authentication
restful API是無(wú)狀態(tài)的也就是說(shuō)用戶請(qǐng)求的鑒權(quán)和cookie以及session無(wú)關(guān),每一次請(qǐng)求都應(yīng)該包含鑒權(quán)證明。
通過(guò)使用ssl我們可以不用每次都提供用戶名和密碼:我們可以給用戶返回一個(gè)隨機(jī)產(chǎn)生的token。這樣可以極大的方便使用瀏覽器訪問(wèn)API的用戶。這種方法適用于用戶可以首先通過(guò)一次用戶名-密碼的驗(yàn)證并得到token,并且可以拷貝返回的token到以后的請(qǐng)求中。如果不方便,可以使用 OAuth 2來(lái)進(jìn)行token的安全傳輸。
支持jsonp的API需要額外的鑒權(quán)方法,因?yàn)閖sonp請(qǐng)求無(wú)法發(fā)送普通的credential。這種情況下可以在查詢url中添加參數(shù):access_token。注意使用url參數(shù)的問(wèn)題是:目前大部分的網(wǎng)絡(luò)服務(wù)器都會(huì)講query參數(shù)保存到服務(wù)器日志中,這可能會(huì)成為大的安全風(fēng)險(xiǎn)。
注意上面說(shuō)到的只是三種傳輸token的方法,實(shí)際傳輸?shù)膖oken可能是一樣的。
緩存
HTTP提供了自帶的緩存框架。你需要做的是在返回的時(shí)候加入一些返回頭信息,在接受輸入的時(shí)候加入輸入驗(yàn)證?;緝煞N方法:
ETag:當(dāng)生成請(qǐng)求的時(shí)候,在HTTP頭里面加入ETag,其中包含請(qǐng)求的校驗(yàn)和和哈希值,這個(gè)值和在輸入變化的時(shí)候也應(yīng)該變化。如果輸入的HTTP請(qǐng)求包含IF-NONE-MATCH頭以及一個(gè)ETag值,那么API應(yīng)該返回304 not modified狀態(tài)碼,而不是常規(guī)的輸出結(jié)果。
Last-Modified:和etag一樣,只是多了一個(gè)時(shí)間戳。返回頭里的Last-Modified:包含了 RFC 1123 時(shí)間戳,它和IF-MODIFIED-SINCE一致。HTTP規(guī)范里面有三種date格式,服務(wù)器應(yīng)該都能處理。
出錯(cuò)處理
就像html錯(cuò)誤頁(yè)面能夠顯示錯(cuò)誤信息一樣,API 也應(yīng)該能返回可讀的錯(cuò)誤信息–它應(yīng)該和一般的資源格式一致。API應(yīng)該始終返回相應(yīng)的狀態(tài)碼,以反映服務(wù)器或者請(qǐng)求的狀態(tài)。API的錯(cuò)誤碼可以分為兩部分,400系列和500系列,400系列表明客戶端錯(cuò)誤:如錯(cuò)誤的請(qǐng)求格式等。500系列表示服務(wù)器錯(cuò)誤。API應(yīng)該至少將所有的400系列的錯(cuò)誤以 json形式返回。如果可能500系列的錯(cuò)誤也應(yīng)該如此。json格式的錯(cuò)誤應(yīng)該包含以下信息:一個(gè)有用的錯(cuò)誤信息,一個(gè)唯一的錯(cuò)誤碼,以及任何可能的詳細(xì)錯(cuò)誤描述。如下:
- {
- "code" : 1234,
- "message" : "Something bad happened <img src="http://blog.jobbole.com/wp-includes/images/smilies/icon_sad.gif" alt=":-(" class="wp-smiley"> ",
- "description" : "More details about the error here"
- }
對(duì)PUT,POST,PATCH的輸入的校驗(yàn)也應(yīng)該返回相應(yīng)的錯(cuò)誤信息,例如:
- {
- "code" : 1024,
- "message" : "Validation Failed",
- "errors" : [
- {
- "code" : 5432,
- "field" : "first_name",
- "message" : "First name cannot have fancy characters"
- },
- {
- "code" : 5622,
- "field" : "password",
- "message" : "Password cannot be blank"
- }
- ]
- }
HTTP 狀態(tài)碼
- 200 ok - 成功返回狀態(tài),對(duì)應(yīng),GET,PUT,PATCH,DELETE.
- 201 created - 成功創(chuàng)建。
- 304 not modified - HTTP緩存有效。
- 400 bad request - 請(qǐng)求格式錯(cuò)誤。
- 401 unauthorized - 未授權(quán)。
- 403 forbidden - 鑒權(quán)成功,但是該用戶沒(méi)有權(quán)限。
- 404 not found - 請(qǐng)求的資源不存在
- 405 method not allowed - 該http方法不被允許。
- 410 gone - 這個(gè)url對(duì)應(yīng)的資源現(xiàn)在不可用。
- 415 unsupported media type - 請(qǐng)求類型錯(cuò)誤。
- 422 unprocessable entity - 校驗(yàn)錯(cuò)誤時(shí)用。
- 429 too many request - 請(qǐng)求過(guò)多。
英文原文:appdesignvault,編譯:@奇風(fēng)余谷