本頁是對維基百科上關於HATEOAS的條目進行修改的版本,該條目使用JSON。在這裡,我們使用HTML來解釋這個概念,並將其與JSON API進行比較。這是一個比維基百科更具主觀性的概念解釋,但在我們看來,它更正確。
超媒體即應用程式狀態引擎(HATEOAS)是REST應用程式架構的一個約束,它將其與其他網路應用程式架構區分開來。
使用HATEOAS,客戶端與一個網路應用程式互動,該應用程式的伺服器透過超媒體動態提供資訊。REST客戶端除了對超媒體的通用理解之外,幾乎不需要事先了解如何與應用程式或伺服器互動。
相比之下,如今基於JSON的網路客戶端通常通過一個固定的介面進行互動,該介面通過諸如swagger之類的工具通過文件共享。
HATEOAS施加的限制使客戶端和伺服器解耦。這使伺服器功能能夠獨立發展。
一個實現HTTP的使用者代理通過簡單的URL對REST端點發出HTTP請求。使用者代理可能發出的所有後續請求都在每個請求的超媒體回應中被發現。這些表示形式使用的媒體類型以及它們可能包含的連結關係是標準化的。客戶端通過從超媒體表示形式中的連結中選擇或通過以其媒體類型提供的其他方式操作表示形式來轉換應用程式狀態。
這樣,RESTful互動是由超媒體驅動的,而不是頻外資訊驅動的。
一個具體的範例將闡明這一點。考慮一下由網路瀏覽器發出的這個GET請求,它會獲取一個銀行帳戶資源
GET /accounts/12345 HTTP/1.1
Host: bank.example.com
伺服器使用HTML回應超媒體表示形式
HTTP/1.1 200 OK
<html>
<body>
<div>Account number: 12345</div>
<div>Balance: $100.00 USD</div>
<div>Links:
<a href="/accounts/12345/deposits">deposits</a>
<a href="/accounts/12345/withdrawals">withdrawals</a>
<a href="/accounts/12345/transfers">transfers</a>
<a href="/accounts/12345/close-requests">close-requests</a>
</div>
<body>
</html>
回應包含以下可能的後續操作:導航到一個UI以輸入存款、提款、轉帳或關閉請求(以關閉帳戶)。
考慮一下稍後的情況,在帳戶透支後。現在,由於此帳戶狀態的更改,可以使用一組不同的連結。
HTTP/1.1 200 OK
<html>
<body>
<div>Account number: 12345</div>
<div>Balance: -$50.00 USD</div>
<div>Links:
<a href="/accounts/12345/deposits">deposits</a>
</div>
<body>
</html>
只有一個連結可用:存入更多錢。在帳戶當前透支的狀態下,其他操作不可用,並且此事實在超媒體中內部反映。網路瀏覽器不知道透支帳戶的概念,甚至不知道帳戶是什麼。它只知道如何向使用者呈現超媒體表示形式。
因此,我們有了超媒體是應用程式狀態引擎的概念。隨著資源狀態的變化,可能的操作也會變化,並且此資訊被編碼在超媒體中。
將上面的HTML回應與典型的JSON API進行比較,後者可能會返回一個帶有狀態欄位的帳戶表示形式
HTTP/1.1 200 OK
{
"account": {
"account_number": 12345,
"balance": {
"currency": "usd",
"value": -50.00
},
"status": "overdrawn"
}
}
在這裡,我們可以發現客戶端必須具體知道status
欄位的值的含義,以及它如何影響使用者介面的呈現,以及可以對其執行哪些操作。客戶端還必須知道必須使用哪些URL來操作此資源,因為它們沒有編碼在回應中。這通常是通過查閱JSON API的文件來實現的。
正是這種對頻外資訊的要求將此JSON API與實施HATEOAS的RESTful API區分開來。
這顯示了兩種方法之間的核心區別:在RESTful的HATEOAS HTML表示形式中,所有操作都直接編碼在回應中。在JSON API範例中,需要頻外資訊才能處理和使用遠端資源。
HATEOAS約束是REST的「統一介面」功能的重要組成部分,正如Roy Fielding的博士論文中所定義的那樣。Fielding的論文是對早期網路架構的討論,當時主要由HTML和HTTP組成。
Fielding在他的部落格中進一步描述了該概念以及超媒體的關鍵要求。
注意:本節的中立語氣存在爭議
在 2000 年代初期,REST 的概念從其最初的早期網路描述的環境中被挪用到了網路開發的其他領域:首先是 XML API 開發(通常使用SOAP),然後是 JSON API 開發。儘管事實上,XML 和 JSON 都不是像 HTML 那樣的自然超媒體。
為了表徵在這些新領域中對REST的不同程度的堅持,提出了理察森成熟度模型,該模型由各種級別的API「成熟度」組成,其中最高級別,第 3 級,由「超媒體控制」組成。
JSON 不是自然的超媒體,因此,超媒體概念只能強加在其之上。試圖達到理察森成熟度模型第 3 級的 JSON 工程師可能會返回以下與上面銀行帳戶範例相對應的 JSON
HTTP/1.1 200 OK
{
"account": {
"account_number": 12345,
"balance": {
"currency": "usd",
"value": 100.00
},
"links": {
"deposits": "/accounts/12345/deposits",
"withdrawals": "/accounts/12345/withdrawals",
"transfers": "/accounts/12345/transfers",
"close-requests": "/accounts/12345/close-requests"
}
}
}
在這裡,「超媒體控制」被編碼在帳戶物件的links
屬性中。
不幸的是,此 API 的客戶端仍然需要了解相當多的其他資訊
GET
請求,以獲取有關相關變化的表示形式嗎?POST
請求,則預期哪些值?將上面的 JSON 與以下 HTTP 回應進行比較,該回應是使用者在點擊第一個 HTML 範例中找到的 /accounts/12345/deposits
連結後,由瀏覽器檢索的
HTTP/1.1 200 OK
<html>
<body>
<form method="post" action="/accounts/12345/deposits">
<input name="amount" type="number" />
<button>Submit</button>
</form>
<body>
</html>
請注意,此 HTML 回應編碼了更新帳戶餘額所需的所有資訊,提供了一個具有 method
和 action
屬性的 form
,以及正確更新資源所需的輸入。
JSON 表示形式不具有與 HTML 表示形式相同的自包含「統一介面」。
將 JSON API 標記為「REST」,無論它們離 RESTful 概念有多遠,都導致 Roy Fielding 說
我對許多人將任何基於 HTTP 的介面稱為 REST API 感到沮喪。今天的範例是 SocialSite REST API。那是 RPC。它尖叫著 RPC。顯示的耦合太多了,應該給它一個 X 評級。
雖然已經嘗試將更精細的超媒體控制強加於 JSON API,但總體而言,業界已經拒絕了這種方法,而傾向於更簡單的 RPC 風格的 API,這些 API 放棄了 HATEOAS 和 RESTful 架構的其他元素。
這個事實強烈證明了這樣一種斷言,即諸如 HTML 之類的自然超媒體是構建 RESTful 系統的實際必要條件。