## REST API ### 前言 REST API 是Resource Representational State Transfer縮寫 Resource:資源。 Representational:表現形式,如JSON,XML... State Transfer:狀態變化。可利用HTTP動詞們來做呼叫。 再講REST API之前我覺得有必要了解一下API,大家都在講的API是什麼 #### API API的全名是 Application Programming Interface,是一種提供不同軟體系統間的互動工具,定義了不同軟體間的互動規範,API允許不同軟體間共享資訊和功能,依照約定好的API接口進行互聯互動, ##### API 簡史 > API起源於1940年代,儘管這個術語直到1960年代和1970年代才出現。現代對API這個術語的使用經常指的是網路API,它們允許通過網際網路連接的電腦之間進行通訊。API的最新發展促進了微服務的流行,這些微服務是通過公共API訪問的鬆散耦合服務。 文字說明肯定不如圖片有趣,所以下面採用網路上找的圖.[來源](https://www.dottedsign.com/zh-tw/blog/product/api) ![image](https://hackmd.io/_uploads/SkGIDJlr1g.png) 有兩種情境: 1. 當你(使用者)走進去一個有服務生的高級餐廳,你想點餐,一定是直接跟服務員溝通,然後服務員溝通完再轉達給廚師,這情境中你就如同使用者,服務員則是溝通的橋樑,廚師就是真的在製作你要的東西的後台. 2. 你(使用者)想要領個錢,你勢必要有一台機器讓你操作,所以提款機就算服務員,他會幫你把你的需求告訴更後面的東西,確認之後再讓你拿到你所需要的$ 這樣做的好處就是,使用者不用去想怎麼做到,只需要開金口就可以拿到自己想要的一切 至於對於商家的好處 1. 提升效率 API讓不同系統間能快速且自動化地交換數據,減少人工操作的時間與錯誤,提高業務運營效率。 1. 擴展業務功能 商家可以通過API整合第三方服務(如支付系統、物流追蹤、行銷工具),快速擴展功能,無需從頭開發。 1. 促進創新與靈活性 API使商家能靈活組合資源,根據市場需求快速開發新產品或服務,保持競爭力。 1. 改善用戶體驗 通過API提供的即時數據與互動,商家能更精準地滿足客戶需求(如個性化推薦或即時服務)。 4. 數據價值最大化 商家能利用API分享或交換數據,與合作夥伴共同開發新商機,或基於數據進行更精準的決策。 6. 支持多渠道整合 API讓商家能輕鬆連接多個銷售或服務平台(如網站、APP、第三方市場),統一管理並觸達更多客戶。 10. 降低開發成本與風險 利用現有的API解決方案,商家可避免自行開發基礎功能,節省成本並縮短產品上市時間。 總體來說,API能幫助商家更高效運營、快速適應市場需求、提升客戶滿意度,並支持業務的數字化轉型。 #### Web API Web API 是一種遠程API,遠程API通常是指不是在本地操作那台主機的資源,Web API也是現在被廣泛利用的API,通常會使用HTTP協定來傳輸請求消息,並提供響應消息的結構,這些響應結構通常是XML或者是JSON文件形式來表示,因為這兩個最簡單操作結構來顯示 ![image](https://hackmd.io/_uploads/HkI93JlH1e.png) 有兩種協定規範SOAP 和 REST 這兩個差別主要是在SOAP是用在XML 寄收上居多並且是依賴在HTTP和SMTP,但現在大多數都在用REST API故這裡不繼續討論 #### REST API 他是一種表述型約束規範架構,他有六個規範要遵守 1. 客端/伺服器架構 REST 架構由客端、伺服器和資源構成,並透過 HTTP 來處理請求。 1. 無狀態 請求所經過的伺服器上不會儲存任何客端內容。與會話狀態相關的資訊會儲存在客端上。 1. 可快取性 透過快取,可以免去客端與伺服器之間的某些互動。 1. 分層系統 客端與伺服器之間的互動可以通過額外的層來進行調解。這些層可以提供額外的功能,如負載平衡、共享快取或安全防護。 1. 按需代碼(可選) 伺服器可以通過傳輸可執行代碼來擴展客戶端的功能。這意味著客戶端可以根據伺服器的回應動態地更新自己的功能或顯示內容,而不需要重新加載所有資源。例如,伺服器可能通過發送 JavaScript 代碼來實現頁面中的即時互動。 > . HTTP 狀態碼 > 200 系列:成功 這些狀態碼表示請求已經成功處理。例如: > 200 OK:請求成功,伺服器回應了所請求的資源。 > 201 Created:請求成功,並且已經創建了新資源(通常是創建一個新物件如使用者資料等)。 > 400 系列:客戶端錯誤 當請求存在問題時,伺服器返回這類狀態碼,通常是因為客戶端發送的請求無法被理解或處理。例如: > > 400 Bad Request:請求格式錯誤或無法被理解。 > 401 Unauthorized:未經授權,需要身份驗證。 > 500 系列:伺服器端錯誤 這些狀態碼表示伺服器處理請求時發生錯誤。即使客戶端的請求沒有問題,伺服器還是無法成功完成處理。例如: > > 500 Internal Server Error:伺服器內部錯誤,通常是伺服器端代碼有問題 1. 統一介面 這項約束是 RESTful API 設計的核心,涵蓋以下 4 個層面: * 識別請求中的資源 請求中的資源會被識別,並與返回給客端的表示內容分離開來。 * 通過不同的表示內容來操縱資源 客端會收到表示不同資源的檔案。這些表示內容必須提供足夠的資訊,以便執行修改或刪除操作。 * 自描述訊息 返回給客端的每個訊息都包含充足的資訊,用於指引客端應該如何處理所收到的資訊。 * 將超媒體作為應用狀態的引擎 在訪問某個資源後,REST 客端應該能夠通過超連結發現目前可用的所有其他操作。 ### 五大操作類型 在講五大action之前必須先談一下冪等性 > 所謂的冪等性指的是任意多次執行所產生的結果都應與第一次執行的結果相同,一般來說服務的調用存在著三種狀態:成功、失敗、逾時,其中逾時的狀態是未知的,當逾時的狀況發生時,為了確保正確調用,可能會進行重送的動作。 #### [冪等性](https://hackmd.io/@Xb1nH7gpQi-pztNr0Nalsw/rJgJKn-H1e) ##### GET 情境:你在電商網站搜尋一件商品,前端會發送 GET 請求到伺服器,請求返回商品清單。 他就是一個純粹你告訴對方,你要什麼資料他就要給你資料而已,他不要說你今天要麵包,他還順便把原有麵包都給換掉一種。 ##### PUT(完整更新) 情境:用戶想要完全覆蓋他們的個人資料,前端會發送 PUT 請求,提交完整的更新資料。 PUT跟PATCH最大的不同是在,PUT通常是在指一次更新完整資料,假設有個人資料是有名字和手機, 你不能只更新名字或手機 ![image](https://hackmd.io/_uploads/r1mNrZgBJx.png) ##### DELETE 情境:用戶決定刪除自己的帳號,前端會發送 DELETE 請求到伺服器,請求移除指定資源。 很簡單明瞭的刪除. #### 非冪等性 ##### POST 情境:你在網站上註冊新帳號,提交表單後,前端會發送 POST 請求,將新用戶數據送到伺服器。 POST有一種嚴格的規定要新增出東西才行,並且他有沒有資料冪等性,本質上已經是多一筆不同的東西 ##### PATCH(部分更新) 情境:用戶想要更新個人資料中的「聯絡電話」,而不是全部資料。前端會發送 PATCH 請求,修改指定欄位。 跟PUT最大不同就是可以做部分更新,如果說是想新增沒有的資料也是PATCH來負責 | **特性** | **PUT** | **PATCH** | |-------------------|---------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| | **用途** | 完整地更新一個資源,通常需要提供整個資源的替代數據。 | 部分更新資源,僅需要提供需要修改的屬性數據。 | | **數據量** | 需要傳遞整個資源數據,包含未變更的部分。 | 只需要傳遞需要變更的數據,數據量通常更小。 | | **冪等性** | 是冪等的,重複相同的請求不會改變資源狀態。 | 一般是冪等的,但可能取決於伺服器的具體實現。 | | **用例** | 需要替換整個資源(例如:重新覆蓋資料庫中的完整記錄)。 | 需要進行局部修改(例如:只更新用戶名稱或狀態)。 | | **效能影響** | 數據較大的情況下,請求的負擔更高,可能會影響效能。 | 數據量小,效能開銷較低,適合頻繁的小範圍修改操作。 | | **規範要求** | RFC 7231 定義,用於將資源存於請求的有效負載中,替代目標資源。 | RFC 5789 定義,用於對資源應用部分更新。 | | **適用場景** | - 更新文件的整個內容<br>- 重置為默認設置<br>- 修改數據時希望確保完整性 | - 更新單一屬性,例如電子郵件地址<br>- 部分數據有必要被變更,例如訂單狀態 | --- ### 路徑命名用法 那分這五大類有什麼好處嗎,就跟蛋豆魚肉類,可以讓大家命名規範 #### 普通案例 獲得商品資料 GET /getAllItems 獲得商品資料 GET /getItem/11 新增商品資料 POST /createItem 更新商品資料 POST /updateItem/ 刪除商品資料 POST /deleteItem/ 若是以使用 RESTful API 開發的話: 獲取商品資料 /GET /items 獲取商品資料 /GET /items/1 新增商品資料 /POST /items 更新商品資料 /PATCH /items/1 刪除商品資料 /DELETE /items/1 #### 一致性 1. 使用正斜線(/)表示層次關係 正斜線(/)用於 URI 的路徑部分,指示資源之間的層次結構關係。例如: ``` http://api.example.com/device-management http://api.example.com/device-management/managed-devices http://api.example.com/device-management/managed-devices/{id} http://api.example.com/device-management/managed-devices/{id}/scripts http://api.example.com/device-management/managed-devices/{id}/scripts/{id} ``` 2. 不要在 URI 中使用尾部正斜線(/) URI 路徑中的最後一個字符如果是正斜線(/),不會添加任何語義價值,反而可能造成混淆,因此最好避免使用 ``` 錯誤範例: http://api.example.com/device-management/managed-devices/ 正確範例: http://api.example.com/device-management/managed-devices ``` 3. 使用連字號(-)提高 URI 的可讀性 為了讓 URI 易於掃描與理解,應使用連字號(-)作為長路徑段名稱的分隔符。 ``` 更可讀: http://api.example.com/inventory-management/managed-entities/{id}/install-script-location 較差: http://api.example.com/inventoryManagement/managedEntities/{id}/installScriptLocation ``` 4. 不要使用底線( _ ) 底線(_)雖然可以作為分隔符,但由於某些瀏覽器或螢幕上可能會將其部分遮擋或完全隱藏,可能會造成混淆。建議改用連字號(-)。 ``` 更可讀: http://api.example.com/inventory-management/managed-entities/{id}/install-script-location 較容易出錯: http://api.example.com/inventory_management/managed_entities/{id}/install_script_location ``` 5. 在 URI 中使用小寫字母 URI 的路徑部分應盡量使用小寫字母,以便於一致性和便利性。 根據 RFC 3986 定義,URI 是區分大小寫的,但協議(如 http)和主機名稱(如 example.com)除外。 ``` http://api.example.org/my-folder/my-doc // 正確 HTTP://API.EXAMPLE.ORG/my-folder/my-doc // 協議部分不區分大小寫,等同於上面 http://api.example.org/My-Folder/my-doc // 錯誤,大小寫不一致 ``` 6. 不要使用文件副檔名 文件副檔名(如 .xml 或 .json)既會使 URI 看起來冗長,也不提供任何額外的好處。因此,建議避免使用它們。 ``` 錯誤範例: http://api.example.com/device-management/managed-devices.xml 正確範例: http://api.example.com/device-management/managed-devices ``` ### 壞處 ##### 性能問題(過多的數據傳輸) 問題描述: REST 通常以 JSON 或 XML 格式返回數據,這些數據可能包含了用戶實際不需要的欄位,導致多餘的數據傳輸。 原因: REST 的設計側重於統一接口和資源抽象,不能按需精確返回用戶需要的欄位。 影響: 在移動設備或慢速網絡環境下,這種不必要的數據傳輸可能影響性能。 例子: 客戶端只需要某個產品的名稱,但 API 返回整個產品的詳細信息(包括價格、描述等)。 ##### 無法高效處理複雜查詢 問題描述: REST 為每種操作設計獨立的端點,不擅長處理複雜的查詢需求。對於多層級或多表關聯數據的獲取,可能需要多次請求。 原因: REST 傾向於以單一資源為核心來設計端點。 影響:請求次數多會增加網絡延遲(N+1 問題)。如果端點數量增多,也會增加 API 的維護成本。 例子: 要查詢用戶的訂單及每個訂單的詳細商品資訊,REST 需要設計多個端點,或者返回一個過於冗長的響應。 ##### 缺乏實時數據支持 問題描述: REST 依賴傳統的 HTTP 通訊,難以支持需要即時數據的應用(例如即時聊天、金融數據推送)。 原因: REST 的請求-響應模型要求用戶主動發起請求,無法實現服務器對客戶端的主動推送。 影響:需要額外實現輪詢(Polling)或使用 WebSocket/Server-Sent Events 等技術,增加了開發與運維複雜性。 替代方案:WebSocket 可以主動推送數據,但和 REST 是不同的設計風格。 ##### 端點的增長與管理困難 問題描述: 隨著系統功能的擴展,端點數量可能迅速增加,導致端點的組織和命名變得混亂。 原因: REST 將每種操作綁定到不同的 URI,很難避免過多的端點。 影響:導致 API 使用和維護難度增加。 使用者可能對錯綜複雜的端點感到困惑。 例子:/users/:id/orders、/users/:id/orders/:orderId 等多層次結構容易造成規模化後的維護難題。 ##### 狀態的處理限制 問題描述: REST 是無狀態的,客戶端需要在每次請求中提供完整的上下文,增加了帶寬使用和開發負擔。 原因: REST 的無狀態特性旨在確保每個請求都獨立處理,但會影響某些狀態相關場景的效率。 影響:在分布式系統中,處理會話相關信息(如購物車)需要額外的解決方案。 無法直接支援長時間持續的會話處理。 ![image](https://hackmd.io/_uploads/SJ-PIn-HJl.png) ##### 版本控制困難 問題描述: 當需要對 API 進行重大更改時,常需要實現版本控制(如 /v1 或 /v2)。隨著版本增多,導致老版本難以維護。 原因: API 的版本控制通常需要明確的策略,但 REST 缺少標準化的版本管理方法。 影響:客戶端可能繼續調用舊版本,增加運維成本。 開發者需為不同版本的 API 提供兼容支持。 替代方案: GraphQL 通過靈活查詢可避免這一問題。 ##### 與 GraphQL 等新技術相比靈活性不足 問題描述: REST 返回的是固定的數據結構,客戶端無法自主選擇數據。 原因: REST API 基於資源設計,對於靈活查詢需求不友好。 影響:在現代前端框架(如 React、Vue)中使用時,需要更多前端處理代碼。 對開發大型、複雜系統時效率低下。 ### 總結 REST 雖然在資源導向的場景下非常強大,但面對實時應用、高頻互動、複雜查詢或靈活數據需求時,其設計限制可能成為痛點。因此,應根據具體應用場景選擇合適的 API 方案,或將 REST 與其他技術(如 WebSocket、GraphQL、gRPC)結合使用來彌補其不足。