RESTful API - fantasy0107/notes GitHub Wiki
- 先看看有沒有可以用的api - 要有 api 文件查詢
- api 要有版本
- 判斷要用的 http method
- 成功和失敗所要回傳的狀態碼
- 回傳格式 ex: json api
是一種設計風格或者規範也就是說不遵守也可以
應該有看到我剛才的 URL 是v1
- 嚴重的效能問題
- 扭曲程式邏輯和數據結構
- 例如 : 以下兩派都有人喜歡
/v1/pets/12
/v1/users/987/pets/12
- 像是在頁面中, 用戶能同時建立其用戶資料, 還有其他貓群的, 所以需要建立特殊的 post - UserAndPet
- 所有的 API一定是名詞或動名詞
- data 與 presentation 混和, presentation 無法單獨 cache , 只要 data 變動就必須重新產生
- 無法徹底分割 presentation, business logic, 和 data 影響開發, 測試和除錯
- 伺服器將 data 和 presentation 整合(data binding), 消耗伺服器資源
- 表面上, 原本只需要 1 次 request 增加為 2次似乎更花時間與網路流量
- 但是, 只要負責美工的同事不改變網頁外表, 第一個 request 伺服器會回答 http 304 not modified
- 網頁 presentation 不用每次重傳, 可以節省不少網路流量($$$$$)
- presentation 和 data 徹底分離
- 開發和測試 presentation 的 data mocking 可以使用專門的 mock api 伺服器
- 只要準備好 api 與測試資料, 前後端工程是就能專心工作, 前端開發延誤和後端工程師無關
- 可在將執行架構改為 presentation 在 apache/cdn, api 為 Tomcat
- 可以不再伺服器做的東西, 就不要放在伺服器
- data binding 交給瀏覽器處理, 不再是伺服器的工作, 省下伺服器的 cpu
- 即使未來要支援 ios, android 只要背後邏輯不變, 這些 API 能全部重複使用, 節省開發時間
只是回歸最初 HTTP 時代的設計哲學 雖然大部分人都是使用 HTTP 來實現 RESTful, 但 RESTful 是設計哲學, 不強制用甚麼方式來實現
- 正解1 : HTTP 只要求 protocol 是 stateless, 從未要求伺服器是 stateless
- 正解2 : RESTful 只要求 application server 是 stateless,server side 其他部分可以是stateful
- 正解: 統一介面(uniform interface)只建議使用 HTTP, 使用其他技術實作的統一介面也能滿足 RESTful 要求
- RESTful 只規範伺服器, 和客戶端與伺服器之間的通訊協定
- 系統內所有的東西都必須定義能否使用快取
- 客戶端建立本地快取
- 下次請求時, 客戶端會把本地快取版本告訴伺服器, 如果伺服器發現資源沒有沒有改動, 返回 304
- 可以省下伺服器 CPU資源和網路流量
- 不常變動的物件適合設定為快取, 如網頁介面
- 詳見 HTTP conditional GET
- 隨時會斷線
- 使用 API, 連線可能在信號送達伺服器前斷線
- 更可能用戶端以為斷線, 卻早已經傳訊成功
- 除非使用 TCP/IP 否則當客戶端先發出 指令1, 然後再發出指令2, 在次序錯亂的情況下, 伺服器可能先收到指令2
- 任何可以錯的東西, 都有機會出錯
- Restful 伺服器端是被允許有狀態性的
- Application Server 和 connection 必須是無狀態的
- RESTful 准許把狀態儲存到資料庫中, 例如將登入狀態的短期資訊放到短期資料庫Redis
- 最簡單的程式寫法: RESTful 禁止使用 HttpSession(Java), session_start(PHP)
- atomic 是由商業邏輯定意的
- 從用戶 A 轉帳到用戶 B
- 付錢買火車票
- 每一個動作都比須是 atomic, 一個完整執行後的 API 呼叫不能讓伺服器數據停留在不一致的狀態
- 另一個說法 : 你不能使用兩個或以上的 API 呼叫去完成一個動作
所有 URL都應該基於物件, 而不是行動
一個物件正常應該有4種行動 查詢, 更改, 誕生, 刪除
- 查詢 : 一般使用 HTTP GET
- 更改 : 一般使用 HTTP PUT/PATCH
- 誕生 : 一般使用 HTTP POST
- 刪除 : 一般使用 HTTP DELETE
GET - 得到檔案 | POST - 新增檔案 | PUT - 更新檔案 | DELETE - 刪除檔案 | |
---|---|---|---|---|
Restful | GET - /api/files/ | POST - /api/files/ | PUT - /api/files/ | DELETE - /api/files/ |
一般 | /api/get_file/ | /api/upload_file/ | /api/update_file/ | /api/delete_file/ |
REST = Resource Representational State Transfer
- Resource => 資源
- Representational => 像是 JSON,XML,YAML 等等...
- State Transfer => 狀態傳輸 ,透過 HTTP 動詞實現 ( GET,POST,PUT,DELETE)
- 單一接口利用 HTTP method
- 可讀性
- 安全性 - 從 URL 判斷出 CRUD 進而操作
是指該操作不會改變伺服器端的資源狀態(而且結果可以被cache)
是指該操作不管做1遍或做n遍,都會得到同樣的資源狀態結果
HTTP | Method Idempotent | Safe |
---|---|---|
OPTIONS | yes | yes |
GET | yes | yes |
HEAD | yes | yes |
PUT | yes | no |
POST | no | no |
DELETE | yes | no |
PATCH | no | no |
- 伺服器收到請求, 並且確定請求沒有問題, 但尚在處理中
- 不過, 這請求需要很多時間來工作, 為了避免客戶白白等待, 即使工作還沒完成, 先回答客戶 工作收到了
- 沒事別亂用
- 與 200 相似, 不過沒有結果須要回傳
- 一般來說 delete 和 put 會用到
- 請求的資源並未修改(通常是用戶端發送了帶有If-Modified-Since或If-None-Match表頭的請求)
- 如果客戶端已經有了某一個物件的副本. 但是不知道這物件是否是最新版
- 客戶端會發出 conditional get, 在 http header 中加入 if-modified-since:<某時間>
- 如果客戶端是最新版, 就回答304否則200
- 用於請求 API 參數不正確的情況,例如傳入的 JSON 格式錯誤。通用狀態碼
- 請求內容有誤伺服器拒絕執行 ex age應該是 integer 但傳來 abc315
- 用於表示請求的 API 缺少身份驗證資訊。
- 最簡單請登入系統
- 請檢察 HTTP header 的 authorization
- 用於表示該資源不允許特定用戶訪問。
- 跟 400 不同, 伺服器明白請求內容
- 不過, 其請求內容與商業邏輯矛盾, 伺服器拒絕執行
- 用於表示請求一個不存在的資源
- 如果 get collection 而沒有搜查到滿足條件的物件, 應該是返回 200 而不是 404
- 用戶正在改動的物件, 已經被別人先改動過了
- 工程師要找bug了, 或是某部分像是資料庫掛了
- 用戶端的請求目前未支援(也就是將來有可能支援)
- 上游的伺服器未回傳正確結果,一般是gateway或proxy server才會回傳此狀態碼
- 伺服器分流層( load balancing tier ) 出現問題
- 暫停服務(也就是過不久就會恢復服務──如果一切順利的話)
- 伺服器沒當掉, 只是太多人使用而繁忙中, 所以直接拒絕這個請求
通訊協定
- Restful 後端
- SOAP
- 支持 REST 介面的資料庫
- HTML
- 資源(Resource) + 方法(Method) 1.非狀態通訊 (stateless protocol)
- 資源一定是名詞
- 動名詞也是名詞
- 常用就 get 和 post 但還有很多其他的
- 一些資源可能只支持部分 method
- /v1/TopSecretReport 應該只有 get
- 讀取資源 (Readonly)
- 只有 get 才用 queryString
- 以 id 結尾通常是讀取單一物件 ex: /v1/users/987
- 沒有以 id 為結尾的讀取 collection
- 可以有 include 去取得主要資源的關聯資源
- 可以有 sort
GET /people?sort=age // 單一 (asc)
GET /people?sort=age,name //多個 (asc)
GET /articles?sort=-created,title (desc)
- 可以有 Pagination - 分頁
- 可以有 Fieldsets - 只取得特定資源和相關關聯資源的欄位
GET /articles?include=author&fields[articles]=title,body&fields[people]=name
- Provide filtering, sorting, field selection and paging for collections
- 刪掉特定資源
- EX: /v1/users/987 - 刪掉使用者987
- 建立資源 ex /v1/users
- 一般會把資源 ID 返回給用戶
- 延伸思考 : 在穩定定網路底下, 用戶建立一份資源時卻發出兩次 post 怎麼辦
- HTTP post 定義為 non-idempotent, 但是他沒有禁止你自行解決 idempotent 的問題
- 自己的觀點 - 也可以用在搜尋和一個商業邏輯的行為(url用動名詞)
- 改動資源的部分內容
- id 是 987 的 user 的內容是: name = susan, age=30, 現在要把 age 改成31 所以
url = /v1/users/987
method = patch
request body = { "age" : 31 }
- 是否是 idempotent 要看你的改動
//idempotent
set age = 31
//non idempotent
set age = age +1
- 傳統 HTTP 定義 : 以新上傳的內容, 覆蓋掉本來的資源
- 不過還多很人會在 put 中支援部分改動 (partial update), 而不再另外開 patch method
- 用來查詢某一資源, 使其能使用的methods
- cross domain request 時, 用戶端會先發出 options 查詢