restful架構

參考1參考2html

RESTful架構,一種互聯網軟件架構。它結構清晰、符合標準、易於理解、擴展方便,因此正獲得愈來愈多網站的採用java

起源 REST這個詞,是Roy Thomas Fielding在他2000年的博士論文中提出的git

Fielding將他對互聯網軟件的架構原則,定名爲REST,即Representational State Transfer的縮寫。這個詞組的翻譯是"表現層狀態轉化",若是一個架構符合rest原則,咱們就稱它爲restful架構github

資源(resources)json

rest翻譯爲表現層狀態轉化,它沒有指名是誰的表現層,缺少主語,在這裏,咱們用資源當作主語,即爲資源的表現層狀態轉化。api

所謂資源,就是網絡上的一個實體,它能夠是一張圖片,一段文本。。。咱們能夠用一個url指向它,用戶經過url就能訪問到這個資源。數組

普及兩個概念 uri與url,uri(統一資源標識符 Uniform Resource Identifier),url(統一資源定位符 Uniform Resource Locator),其中url是uri的子集服務器

表現層(representation)restful

資源是一種信息實體,它能夠有多種外在表現,好比文本能夠以txt格式表現,也能夠用html,json,xml格式表現,咱們把資源具體呈現出的形式叫作它的表現層。網絡

uri指向資源,但不表明資源的形式,http頭部中的accept和content-type等表達了資源的形式

狀態轉化(state transfer)

訪問一個uri,就表明客戶和服務器發生了一個交互,這個過程會涉及到數據和狀態的變化。

互聯網通訊協議http協議,是無狀態的,不能記錄資源的各類狀態,資源的狀態保存在服務器端,若是要操做服務器上的資源,就要經過一些手段,讓服務器知道,從而讓服務器的資源發生狀態轉化,這個變化是創建在表現層之上的,就是表現層狀態轉化。

客戶端使用的手段,只能是http協議,http協議裏有不少操做方式的動詞好比get,post,put,delete,它們對應了四種基本操做,get用來獲取資源(查),post用來新建資源(增)或者修改資源(改),put用來更新資源(改),delete用來刪除資源(刪)。

綜上

restfull架構即爲

每一個url指向一種資源,客戶端和服務器之間傳遞資源的某種表現層,客戶經過4個http動詞,對服務器資源進行操做,實現服務器資源表現層狀態轉化

常見誤區

url中含有動詞,好比/users/update/1,其中update是動詞(手段),這個url就不知足restful架構,正確的寫法是/user/1,而後用put方式或post方式

url中帶有版本號,不一樣版本,能夠理解爲同一資源的不一樣表現形式,能夠把版本號放到http頭信息中,從url剔除

 restful api設計

1、協議

api與用戶的通訊協議採用http協議

2、域名

儘可能將api部署到專用域名下,好比 http://api.test.com。若是api很少且比較簡單,不太會進一步擴展,也能夠放到主域名下,好比http://test.com/api/...

3、版本(version)

將版本號放到http頭信息中,也有說法說版本號放到url中更方便直接,github的是放在http頭信息裏的

4、路徑(endpoint)

路徑又稱「終點」(endpoint),表示api具體網址,在restful架構中,每一個網址表明一種資源(resource),因此網址中不能有動詞,好比說一個api提供動物園zoo信息,其中包括各類動物以及僱員信息,符合restful架構的url可以下設計

  • http://api.test.com/zoos 
  • http://api.test.com/animals
  • http://api.test.com/employees
  • http://api.test.com/zoo/1

5、http動詞

對於資源的具體操做類型,由http動詞表示,經常使用的http動詞以下

  • get(select),從服務器獲取資源(一項或多項)
  • post(create),在服務器新建一個資源
  • put(update),在服務器更新資源(客戶端提供改變後的完整資源)
  • patch(update),在服務器更新資源(客戶端提供改變的屬性)好比svn中針對修改打patch操做
  • delete(delete),從服務器刪除資源

兩個不經常使用http動詞

  • head,獲取資源元數據
  • options,獲取信息,關於資源的哪些屬性是客戶端能夠修改的

例子以下

  • get /zoos,獲取全部動物園
  • post /zoos,新建一個動物園
  • get /zoo/id,獲取某個指定動物園的信息
  • put /zoo/id,更新某個指定動物園信息(提供該動物園修改後的完整信息)
  • patch /zoo/id,更新某個指定動物園信息(提供該動物園部分信息)
  • delete /zoo/id, 刪除某個動物園
  • get /zoos/id/animals,獲取指定動物園的全部動物
  • delete /zoos/id/anamal/id,刪除指定動物園的指定動物

6、信息過濾(filter)

若是資源數量過多,服務器很差一次性所有返回給用戶,api應該提供參數,過濾返回結果,好比指定篩選條件,排序,分頁,限制返回數量等

  • ?animalType=1,指定篩選條件
  • ?sort=age&order=desc,排序
  • ?page=2&perPage=10,分頁
  • ?limit=10,限制返回數量

參數設計容許冗餘,即容許api路徑與url參數偶爾重複,好比 get /zoos/id/animals與 get /animals?zooId=id含義相同

7、狀態碼(status code)

服務器向用戶返回的狀態碼和提示信息,常見的列表如下

  • 200 OK - [get],服務器成功返回用戶請求的數據,該操做是冪等的(idempotent)
  • 201 CREATED - [post/put/patch],用戶新建或修改數據成功
  • 202 ACCEPTED - [*],表示請求已進入後臺排隊(異步任務)
  • 204 NO CONTENT - [delete],用戶數據刪除成功
  • 400 INVALID REQUEST - [post/put/patch],用戶發出的請求錯誤,服務器沒有進行新建或修改數據的操做,該操做冪等
  • 401 Unauthorized - [*],用戶沒有權限(令牌,用戶,密碼錯誤)
  • 403 Forbidden - [*],表示用戶獲得受權(與401錯誤相對),可是訪問是被禁止的
  • 404 NOT FOUND - [*],用戶發出的請求針對的是不存在的記錄,服務器沒有進行操做,該操做冪等
  • 406 Not Acceptable - [get],用戶請求的格式不可得(好比用戶請求json格式,可是隻有xml格式)
  • 410 Gone - [get],用戶請求的資源被永久刪除,且不會再獲得
  • 500 INTERNAL SERVER ERROR - [*],服務器發生錯誤,用戶將沒法判斷髮出的請求是否成功

8、錯誤處理(error handling)

 若是狀態碼是4xx,應該向用戶返回錯誤信息,通常來講,返回的信息中將error做爲鍵名,出錯信息做爲鍵值便可

9、返回結果

針對不一樣操做,服務器向用戶返回的結果應該符合如下規範

  • get /collection 返回資源對象的列表(數組)
  • get /collection/resource 返回單個資源對象
  • post /collection 返回新生成的資源對象
  • put /collection/resource 返回完整的資源對象
  • patch /collection/resource 返回完整的資源對象
  • delete /collection/resource 返回一個空文檔

10、hypermedia api

restful api最好作到hypermedia,即返回結果中信息豐富一點,提供連接,連向其餘api方法,使得用戶不用去查詢文檔,也知道下一步應該作什麼。好比當用戶向api.test.com的根目錄發出請求時,獲得的文檔包含如下結果

{
"link":{ "rel": "collection http://api.test.com/zoos",
     "href": "http://api/test.com",
     "title": "list of zoos",
     "type": "application/vnd.yourformat+json"
} }

 上面代碼表示,文檔中有一個link屬性,用戶讀取這個屬性就知道下一步該調用什麼api,rel表明這個api與當前網址的關係(collection關係,並給出該collection網址),href表示api路徑,title表示api的標題,type表示返回類型。

hypermedia api的設計也被稱爲HATEOAS,github的api就是這種設計,請求github的api會獲得一個全部可用api網址列表

{
  "current_user_url": "https://api.github.com/user",
  "current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",
  "authorizations_url": "https://api.github.com/authorizations",
  "code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
  "commit_search_url": "https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}",
  "emails_url": "https://api.github.com/user/emails",
  "emojis_url": "https://api.github.com/emojis",
  "events_url": "https://api.github.com/events",
  "feeds_url": "https://api.github.com/feeds",
  "followers_url": "https://api.github.com/user/followers",
  "following_url": "https://api.github.com/user/following{/target}",
  "gists_url": "https://api.github.com/gists{/gist_id}",
  "hub_url": "https://api.github.com/hub",
  "issue_search_url": "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
  "issues_url": "https://api.github.com/issues",
  "keys_url": "https://api.github.com/user/keys",
  "notifications_url": "https://api.github.com/notifications",
  "organization_repositories_url": "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
  "organization_url": "https://api.github.com/orgs/{org}",
  "public_gists_url": "https://api.github.com/gists/public",
  "rate_limit_url": "https://api.github.com/rate_limit",
  "repository_url": "https://api.github.com/repos/{owner}/{repo}",
  "repository_search_url": "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
  "current_user_repositories_url": "https://api.github.com/user/repos{?type,page,per_page,sort}",
  "starred_url": "https://api.github.com/user/starred{/owner}{/repo}",
  "starred_gists_url": "https://api.github.com/gists/starred",
  "team_url": "https://api.github.com/teams",
  "user_url": "https://api.github.com/users/{user}",
  "user_organizations_url": "https://api.github.com/user/orgs",
  "user_repositories_url": "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
  "user_search_url": "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
}

從上面能夠看到,若是想獲取當前用戶的信息,應該去訪問api.github.com/user,會獲得以下返回結果

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3/users/#get-the-authenticated-user"
}

返回結果給出了服務器的提示信息,以及相應文檔地址

11、其餘

api的身份認證可使用Oauth框架

服務器返回的數據格式,儘可能使用json,xml

 

自動化測試工具java版參考

相關文章
相關標籤/搜索