iT邦幫忙

2

[不做怎麼知道系列之Android開發者的30天後端養成故事 Day22] - 什麼是真正的 RESTful API? #RESTful API應該長什麼樣子? #六規則 #湊個第三項

Sam 2020-03-02 00:18:142666 瀏覽

https://ithelp.ithome.com.tw/upload/images/20200302/20124548Px62pXJjOW.png

哈囉,我們又見面了,前幾天我們把整個 Django 網站搬到雲端了,今天我們來研究一下 RESTful API,到底什麼樣的 API 才叫做 RESTful 呢 ? 讓我們繼續看下去。

什麼是 REST ?

REST 的全名是 Representational State Transfer,而這套 REST 架構是由 Roy Fielding2000年博士論文提出,恩,有點老舊了,不過沒關係,畢竟它還是經典,而 RESTful API,表示符合 Representational State Transfer 架構的 API 們,就叫做 RESTful API

在我寫這篇文章的時候,發現有個新興的開 API 的方法叫做 GraphQL,之後再來瞭解,今天就先看看經典且傳統的 REST 架構。

在了解細部之前,你需要先知道

怕等等有太多專有名詞,要先來個簡介,什麼是 API,和 serve-client 架構,以及 CRUD 操作,先看看短片吧,短片會替我解釋 XD

建議瞭解這些基本的專有名詞之後,你再往下面看下去,不然你應該會看得霧煞煞。

真正的 REST 來了

其實,人人都會開 API 或使用 API,那麼到底有沒有 REST,差在哪裡 ? RESTful API 又應該長什麼樣子呢 ? 符合哪些條件,才可以算是真正的 RESTful API 呢 ?

本篇參考

符合這六條件,才叫做真正的 REST

這六條件的順序不影響,前五條是必須遵守才叫做真正的 REST,而第六條可視情況選擇。

  1. Uniform interface (介面一致,API 邏輯一致)
  2. Stateless (無狀態的 Server 端)
  3. Client-server (Client端 和 Server端 分離)
  4. Cachable (可暫存的資源)
  5. Layered System (分層的系統架構)
  6. Code on demand (Optional) (視情況決定要不要遵守,Server端 可以傳送可執行的程式碼給 Client端)

但其實沒有符合真正的 REST 也無所謂,就像寫程式不一定要套用 Design Pattern、也不一定要遵守 SOLID 原則,但這些原則和架構,就是用來把 "痛過的" 經驗 SOP 化,告訴世人這樣做比較好。

REST 條件一、Uniform Interface (介面一致,API 邏輯一致)

原文:Once a developer becomes familiar with one of your APIs, he should be able to follow similar approach for other APIs.

( 開發者只要熟悉你的一支 API,他就應該能用同樣的邏輯,來理解你開出來的其他 API )

舉例來說,我開出一支 GET http://rs.com/api/articles,可以拿到 RS 寫的所有文章,那麼你可以期望,我會有另一支 API 是 GET http://rs.com/api/articles/1/title,可以拿到 id=1 的文章標題,照這樣的邏輯,那麼可能就會有 GET http://rs.com/api/articles/1/content/,可以拿到 id=1 這篇文章的內文。

把這三隻 API 抓出來看,你會發現風格一致,且邏輯也一致,這樣就符合第一點 Uniform interface 的條件,再新增幾條風格一致的 API 一起看更有感覺。

  • GET http://rs.com/api/articles
  • GET http://rs.com/api/articles/1/title
  • GET http://rs.com/api/articles/1/content
  • DELETE http://rs.com/api/articles/1
  • POST http://rs.com/api/articles

上面的範例隱含了以下兩點的假設基礎

  • Resource-based (以 資源 為基礎)

    透過 RESTful API,我們可以把資源(可能是 圖片、文字、用戶資料 等等)傳送給 client端,而且可以是多指向一,也就是允許多個 API 指向同一個資源,舉例來說,一個 API 長這樣 GET http://rs.com/articles/1,那麼它代表的是可以拿到我的 id=1 的文章,而 DELETE http://rs.com/articles/1 就是代表要刪掉我的 id=1 的文章。

  • Representations (把 資源 呈現的方式)

    透過 RESTful API,Server端 把 資源 以 JSONXML 的形式呈現,假設有一個 Article 的資料,client端 透過 GET http://rs.com/articles/1,而 server端 回傳一個 JSON 的資料

    {
        "id": 1,
        "title": "What is RESTful API?",
        "content": "哈囉,我們又見面了,...",
        "created": "2020-03-01 10:03:33",
        "updated": "2020-03-01 22:12:57"
    }
    

REST 條件二、Stateless (無狀態的 Server 端)

No client context shall be stored on the server between requests. The client is responsible for managing the state of the application.

( 在 server端 不儲存 client端 的狀態資訊 (context),而是由 client端 來掌握 app 的狀態 )

需要先解釋 context ,如果你把 context 丟翻譯,會出現 語境語意上下文 等等讓人摸不著頭緒的字眼,我在開發 Android 時,跟 Android 的 context 相處了好久,才弄懂 context 的意思,但弄懂之後,才發現這個詞到哪邊都是通用的。

簡單來說,在這邊所指的 context 包含了你在網站進行的任何行為,你點了一個按鈕是一個 context、瀏覽一個頁面是一個 context、登入帳號是一個 context、結帳下單是一個 context。

原文所提到的 server端 不應該儲存 client context,這麼一說,難道我不用登入就可以下單了嗎 ?! 其實不是,這涉略到 authentication(驗證) 和 authorization(授權),可以參考 (2015) How to understand “RESTful API is stateless”? 這篇,有我覺得蠻好理解的解釋,關於 authentication,所有能夠證明用戶身分的資訊,必須包含在一個 request 裡,而不是由 server 儲存資訊。

https://ithelp.ithome.com.tw/upload/images/20200302/20124548r9EPkedBZE.png

以上面自己做的圖來解釋,如果有保存狀態的後端架構下,同時又做了 load balance 機制的例子,如果今天有個客戶來我的電商網站登入了,然後下單一項商品,當他下單的時候發現跳出一個訊息說「請登入,才能下單」,心裡一定會很不爽,因為明明登入過了,卻還要再登入一次,那有可能是因為 Server1 儲存了身份驗證的狀態,可是真的要下單時,由於有設定 load balance 的機制,可能下單的 request 導向了另一台 Server2Server2 卻不知道客戶在 Server1 所做的事情做到哪裡了。

以上的例子有點像是 打客服專線,你每次打客服專線,可能都是不同的客服人員接聽,每個不同的客服人員,不會知道你在上一通,跟前一位客服人員講了什麼。

那麼代表我的每個 request,都要包含用戶的帳號密碼嗎? 這樣做有點蠢,所以就有其他的驗證方式出現,例如可以把帳號密碼驗證之後,轉成 token 方式,token 可能包含加密過的帳號密碼、過期時間,有各種 token,像是Basic authenticationJson Web Token(JWT)、Bearer token

Stateless 是有優點的,這代表狀態不會被儲存在你的任何一個伺服器上,這樣你的伺服器就可以擴大增長,變成分散式,依舊可以參考 (2015) How to understand “RESTful API is stateless”?

REST 條件三、Client-server (沒什麼好翻譯的,就是 server 和 client 分開且獨立)

原文: Servers and clients may also be replaced and developed independently, as long as the interface between them is not altered.

( 只要中間的 API 沒有變,Server 和 Client 可以個別開發,相互不受影響 )

https://ithelp.ithome.com.tw/upload/images/20200302/20124548QDFpFkqFDV.png

這很好理解,也就是說 RESTful API 開出來之後,只要 API 不動,你的 client端 應該要可以不受 server端 的開發推進所影響;同理,你的 server端 應該要不受 client端 的開發推進影響。

REST 條件四、Cacheable (可暫存的資源)

原文: Well-managed caching partially or completely eliminates some client-server interactions, further improving scalability and performance.

( 好的 Caching 能部分或完全消滅 client 和 server 間的互動,更能夠改善 scalability 和 performance )

https://ithelp.ithome.com.tw/upload/images/20200302/201245480ouMAG3Nvq.png

這點也很好理解,當你把資源拆成獨立的部分,就能針對不同資源做暫存,看有哪些常用的圖片 或 常被瀏覽的頁面,就把這些常用的資源,獨立出來放著,這樣當重複被使用時,就直接從暫存裡面拿出來就好,不需要再透過 server 到資料庫裡面去撈。

REST 條件五、Layered system (分層的系統架構)

原文: REST allows you to use a layered system architecture where you deploy the APIs on server A, and store data on server B and authenticate requests in Server C, for example. A client cannot ordinarily tell whether it is connected directly to the end server, or to an intermediary along the way.

( REST 允許使用分層的系統架構,舉例來說,你把 API 放在 ServerA、資料放在 ServerB、處理驗證在 ServerC,對於 client端 而言,無法分辨到底是跟哪一個 Server 在對話 )

也就是說,應該要把 功能(講 功能 不太對,但我不知道要用什麼詞QQ) 拆成多層,每層各司其職,也要能夠重複利用各個層的功能,補充說明可以參考 (2015) Layered system constraint in REST API | StackOverflow

https://ithelp.ithome.com.tw/upload/images/20200302/20124548daslJP2zkX.png

以上面自己做的圖為例,一個有分層的 Server,分成了 DB ServerAuthentication ServerWeb Server,而 Client端 可能有 Web clientMobile client,其中 Web client 會用到三個 Server,然而 Mobile client 它不需要 Web server 的資料呈現方式,那麼因為 Server 有分層的關係,Mobile 可以只跟 DB ServerAuthentication Server 以 RESTful API 要資料即可,可重複利用這些 Server 的 RESTful API,所以不需因為 Mobile 不需要某一個部分,而更動到 Server 的系統架構。

REST 條件六、Code on demand (Optional,隨需求傳可執行的程式碼,可依情況選擇要不要遵守這條規則)

原文:Well, this constraint is optional. Most of the time, you will be sending the static representations of resources in the form of XML or JSON. But when you need to, you are free to return executable code to support a part of your application, e.g., clients may call your API to get a UI widget rendering code. It is permitted.

( 多數情況下是由 server 傳靜態資源給 client,但如果有需要,也可以傳可執行的程式碼給 client 去執行 )

你如果有看過一些網站的原始碼,有些網站會在 html 用上 <script> 的標籤,就會大概理解這條規則的意思,這些 <script> 的標籤內的程式碼,就是當你瀏覽網頁時會執行的 javascript。如果是沒有特殊廣告或是動畫的部落格,只是純粹呈現文字的文章的話,那麼就不會用到動態執行 javascript 的功能,所以作者才會說,這條規則可以選擇性的使用。

單日心得總結

其實寫這篇花的時間比我想像的還要長,需要自己想一些比較貼近我所理解的 REST 的例子,還有把 圖做出來比較好理解。然後找 REST 相關資料的時候,發現中文文章的解釋都蠻零碎的,很難以系統性來理解 REST,通常逛完一圈,得到的只有 REST格式,但其實還不是很懂設計 REST 的核心精神,在找資料的時候,就很想知道採用 REST 架構有什麼優點,最後總結一句「讓人好理解、開發擴充方便」。

不過 REST 也有缺點,如果我今天要透過 API 撈的資料比較複雜,就需要打很多次 API 才能拿到所有的資料,像是需要查詢 文章購買紀錄 的交互關係,那我就需要分別取 文章列表 和 使用者的購買紀錄,如果是更複雜的商業邏輯,則會很浪費網路流量而且速度變慢,所以新的 GraphQL 架構隨之誕生,提供更直覺的資料取用方式。

俗話說的好:「寫 API 是需要美感的」,這種美感需要多看、多做來培養,不是光是這樣看完 REST 六個條件,就知道怎麼開出漂亮的 API 的 XD

我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。


https://ithelp.ithome.com.tw/upload/images/20200219/20124548meDsnCPamL.png


尚未有邦友留言

立即登入留言