Re: [討論] API沒資料,回200還是404比較好
這篇就不以引述的方式回覆了,因為算是對
後續其他人不論在推文中或是回文中的內容
回覆,另外也是針對我自己在前一篇文章中
沒有提到的部分進行說明。
(1) 敘述問題與回答問題
我不知道這裡有多少人上過 jserv的課,如
果有的話,他會頻頻強調不要「舉燭」。從
推文和回文中可以看到,其實不論是發文者
還是回答者,似乎並沒有很正視這個問題…
…
回到最一開始的問題:
「API 沒資料要回傳 200 還是 404?」
‧什麼樣的 API 呢?
‧什麼樣的場景下設計的呢?
‧什麼樣的狀況叫做沒資料?
‧有沒有基於什麼規範或風格?
‧調用的人是誰?
‧你怎麼想的呢?
如果沒有敘述清楚,要人怎麼回答呢?我想
分享一下兩段文字:
https://i.imgur.com/JWMQJjn.png
[來源] http://hhp.li/43pp7h
你真的想要得到的答案是這樣的嗎?
「公司前輩這樣做就這樣做啦!」
「為了方便,問就是 404 一把梭!」
這樣可以得到什麼成長嗎?你認為去有規模
的公司面試問到這樣的問題時,用這樣的回
答可以拿到 Strong Hire?老實說,這樣的
提問方式和不明就理的回答方式,只會讓社
群的風氣變得越來越糟。
(2) 不是只有 REST 一種設計風格
雖然在前一篇文章中以及推文中,我主要都
以 REST 風格的敘述為主,但那個前提是我
認為那樣的問題敘述下,原 po 的問題是在
下述兩種不同情境下,採用 REST 風格而有
所誤解:
---
[GET] /users
[GET] /users/<USERNAME>
上述沒有資料的情形會有兩種:
‧在 users 中沒有任何 user
→狀態 200 並返回 [] 於 body
‧名稱為 <USERNAME> 的 user 不存在
→狀態 404 視情況返回 body
---
但這並不代表實際開發就只有 REST 這一種
以資源為導向的風格,還有 RPC這種以方法
為導向的風格,比如早期可以見到 SOAP 的
身影,近期為了更好地適應某些場景以及發
揮 HTTP2 的優勢,還可以選擇 GraphQL 或
是 gRPC 。如果是區塊鏈的開發者,應該更
常透過 JSON-RPC 協議讀取數據。
比如以登入、搜尋等業務,就不是很好將這
兩個操作抽象為資源,並以 REST 實作。當
然要實作也並無不可,比如常見地將登入行
為改以 session 資源的創建、查詢與刪除…
這很要求開發者的抽象能力,並且對於複雜
業務來說侷限性很大;或者當我只需要文章
的標題與發表時間,以 REST 實作就會拿取
冗贅的資料。
當然,他們都各有優缺,也需要開發人員去
做取捨的。我建議拿上述關鍵字去搜一下差
異,包含 payload和調用方法等;想再了解
更多可以參考各個團隊的技術文章,我會整
裡幾篇放在最後的參考資料中。
(3) 考量資源限制與團隊協作
後面的回覆中,有板友提及了傾向於使用特
定狀態碼是為了方便前端介接;也有板友提
及企業內部設備會攔截特定狀態碼。這些的
確都是實務上的限制與考量,為了讓開發順
暢必須要溝通與協調的,有時候為了時程和
和外部限制(比如客戶其實沒這麼聰明又要
求很多),當然是以能跑為第一前提……
不過這點其實我想稍微糾正一下,但必須先
說這不是所有團隊都適用,就是「不能只有
自己爽」這件事情,有時候還請三思一下是
誰在自己爽。
---
前提狀況如下:
‧以 REST 風格設計
‧接口 [GET] /users/<USERNAME>
‧<USERNAME> 不存在時返回 200 而非 404
好的,前端可以快速知道今天是後端的接口
壞掉還是正常;但是出問題時,後端要怎麼
判斷是不是參數錯誤呢? DevOps/SRE 負責
監控狀態,然後一片都 200看起來很正常,
但是使用者說資料都空的,怎麼排查?
透過正確的 HTTP Status Code 可以很快地
讓後端和 DevOps/SRE 定位原因,如果都是
200 的話,需要每一個狀態都打開查看內容
才能判斷,這真的是個好方式嗎?
在後端看來,他依照 REST 風格和 HTTP 規
範設計,是他為了自己爽嗎?
---
即使進到 exception也能夠根據狀態碼再去
處理,而狀態碼 404 也能夠攜帶 body而不
是就沒有了內容;至於前端的請求函數庫,
以 axios 來說可以自定義 validateStatus
調整 reject 的範圍吧?
今天前端會呼叫 API有八成的狀況是採取了
AJAX 方式,獲取資料於頁面上渲染,如果
能夠接受圖片、影片也是以 URI的方式鑲嵌
在你的 HTML 中,實際上被渲染出來也是由
瀏覽器對 URI發送請求獲取資源,取得後再
渲染在頁面上,圖片網址錯誤無法訪問時,
對 Nginx/Apache 來說也是返回 404 呀!
如果是 JSON 返回一項資源,比如文章內容
或使用者資訊時,這時候網址錯誤時返回同
樣的 404為什麼就這麼難以接受呢?
> 我從 /users/posts 拿到了 pid = 256
> 但是 /posts/256 卻 404
> 權限不夠或是真的沒有這篇文章
> 回去檢查為什麼 /users/posts 吐出 256
(抱歉上述是以網頁應用程式為敘述,我知
道對於移動端開發來說,Android 跟 Swift
下的一些 HTTP 請求框架也有問題,但我不
熟,就再請熟悉的板友幫忙補充了…)
另外 REST 風格真的不善於處理混合多種資
源的狀況,交給 GraphQL 處理會爽很多…
(4) 前端頁面?API?
以 GitHub 來說,訪問以下頁面:
https://github.com/love99067333/
https://github.com/search?q=3123sadq
上述兩個網址都是交由伺服器端渲染返回,
並非由 AJAX 呼叫他們自家的 REST API 獲
取資料再渲染於頁面中。以前一篇所說明的
REST 風格設計來說,此時的「頁面」就是
「資源」,分別請求的是「使用者頁面」和
「搜尋 3123sadq 的結果頁面」。
他也符合 RFC 723x 中對於狀態碼的陳述,
所以對於有資源且存在的使用者頁面返回狀
態碼 200;而對搜尋結果頁面也是 200;而
對於使用者不存在或不願顯示的私密倉庫,
就會是 404 了。
---
如果是 GitHub 對於 search 的 REST 實作
,可以參考這裡:
https://docs.github.com/en/rest/search
BASE_URL 是 https://api.github.com/
你會發現:
[GET] /search
→ 404
(沒有 search 這個資源)
[GET] /search/code
→ 422
(有 search/code 這種資源,但可能參數不足)
[GET] /search/code?q=repo:octocat/Spoon-Knife+css
→ 200
(有 search/code 這種資源,而且參數正確)
[GET] /search/cars
→ 404
(沒有 /search/cars 這種資源)
---
這時候不應該以資料夾路徑的角度去看待這
個資源,上述 REST 實作時,他不是以檔案
系統的方式來呈現資源的;也不是以頁面型
態呈現資源的。
老實說,他們家的 REST API 對我來說堪稱
楷模,因為把很多資源的抽象都做得非常優
秀……但在下面這篇文章中,也坦言存在缺
點並增添了 GraphQL API:
http://hhp.li/4anhqf
(5) 參考資料
‧API Design Guide (Google Cloud APIs)
http://hhp.li/4afqel
同時考慮了 REST API 和 RPC API 設計
對於常用的 Standard Methods 多採用了
REST 風格,而 Custom Methods 多採用
RPC 風格。
‧Best Practices for Designing a
Pragmatic RESTful API
http://hhp.li/4a5n57
應該是多數 REST 使用者都曾經看過的最
佳實踐文章
‧訪問遠程服務(鳳凰架構)
http://hhp.li/4a43xw
中國一本開源的架構著作,作者是 Java
知名書籍作者,這一章節很詳細地介紹了
REST 和其優缺點
‧一把梭:REST API 全用 POST
http://hhp.li/4685dk
‧A preview of the new Dropbox API v2
http://hhp.li/4a8xqy
簡化 HTTP 使用多採 POST 請求,並簡化
錯誤代碼的使用,採 RPC-Style 設計
(6) 後記
還是要再說一次,在新創團隊和開發資源有
限的小公司中,上面提到的東西都不一定適
用……
不可能期待一間只有三人的新創還要搞上各
種測試跟各種優化還要部署 CI/CD 吧? 但
沒辦法去到這些公司體驗文化的話,從書上
和這些大廠的技術文章來吸收跟思考,是可
以做的(當然,他們內部也可能有例外跟分
歧)
說真的這個問題可以展開來說的東西太多了
,包括瀏覽器在輸入一個網址後會經歷哪些
過程和行為,還有網頁前後端的開發…今天
你是不是走前後端分離架構;如果純粹由伺
服器渲染,還要再分中間有沒有微服務或中
間件處理,或者後端直接訪問資料庫塞資料
給模板返回就好;是否一定要在 HTTP 協議
實現你的 API?甚至是前面有人提到的狀態
碼進異常,如果前端後端都不想要修改,有
沒有什麼處理的方式?
前陣子那串「對技術沒熱情是不是不適合這
行?」應該許多人都還記憶猶新,藉著這串
再問問文章一開始的問題:
‧如果是 Junior 的開發者,那樣的發問方
式,真的能得到解答?
‧你不追問不細問,有多少人願意主動發現
你沒問出的問題?
‧沒人回答你,你就不找答案了嗎?有人回
答你,你就直接接受了嗎?
‧如果是 Senior 的開發者,對於提問時要
不要去挖掘後面的問題?要挖到什麼程度
?
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.82.214.46 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1656172096.A.5AE.html
推
06/25 23:53,
1年前
, 1F
06/25 23:53, 1F
推
06/26 00:13,
1年前
, 2F
06/26 00:13, 2F
推
06/26 00:51,
1年前
, 3F
06/26 00:51, 3F
推
06/26 00:53,
1年前
, 4F
06/26 00:53, 4F
推
06/26 01:33,
1年前
, 5F
06/26 01:33, 5F
推
06/26 01:47,
1年前
, 6F
06/26 01:47, 6F
推
06/26 01:56,
1年前
, 7F
06/26 01:56, 7F
推
06/26 06:52,
1年前
, 8F
06/26 06:52, 8F
推
06/26 06:57,
1年前
, 9F
06/26 06:57, 9F
推
06/26 08:54,
1年前
, 10F
06/26 08:54, 10F
推
06/26 09:46,
1年前
, 11F
06/26 09:46, 11F
推
06/26 09:57,
1年前
, 12F
06/26 09:57, 12F
推
06/26 10:00,
1年前
, 13F
06/26 10:00, 13F
推
06/26 10:16,
1年前
, 14F
06/26 10:16, 14F
推
06/26 10:17,
1年前
, 15F
06/26 10:17, 15F
推
06/26 10:31,
1年前
, 16F
06/26 10:31, 16F
推
06/26 11:10,
1年前
, 17F
06/26 11:10, 17F
推
06/26 11:18,
1年前
, 18F
06/26 11:18, 18F
→
06/26 11:18,
1年前
, 19F
06/26 11:18, 19F
→
06/26 11:18,
1年前
, 20F
06/26 11:18, 20F
→
06/26 11:18,
1年前
, 21F
06/26 11:18, 21F
推
06/26 12:32,
1年前
, 22F
06/26 12:32, 22F
推
06/26 12:54,
1年前
, 23F
06/26 12:54, 23F
→
06/26 12:55,
1年前
, 24F
06/26 12:55, 24F
→
06/26 12:56,
1年前
, 25F
06/26 12:56, 25F
推
06/26 13:54,
1年前
, 26F
06/26 13:54, 26F
推
06/26 14:02,
1年前
, 27F
06/26 14:02, 27F
推
06/26 14:10,
1年前
, 28F
06/26 14:10, 28F
推
06/26 14:25,
1年前
, 29F
06/26 14:25, 29F
推
06/26 14:32,
1年前
, 30F
06/26 14:32, 30F
推
06/26 14:34,
1年前
, 31F
06/26 14:34, 31F
推
06/26 15:02,
1年前
, 32F
06/26 15:02, 32F
推
06/26 15:19,
1年前
, 33F
06/26 15:19, 33F
推
06/26 15:42,
1年前
, 34F
06/26 15:42, 34F
推
06/26 15:57,
1年前
, 35F
06/26 15:57, 35F
推
06/26 16:28,
1年前
, 36F
06/26 16:28, 36F
推
06/26 16:44,
1年前
, 37F
06/26 16:44, 37F
推
06/26 17:03,
1年前
, 38F
06/26 17:03, 38F
推
06/26 17:04,
1年前
, 39F
06/26 17:04, 39F
推
06/26 17:10,
1年前
, 40F
06/26 17:10, 40F
推
06/26 17:13,
1年前
, 41F
06/26 17:13, 41F
推
06/26 17:34,
1年前
, 42F
06/26 17:34, 42F
→
06/26 17:34,
1年前
, 43F
06/26 17:34, 43F
推
06/26 18:09,
1年前
, 44F
06/26 18:09, 44F
推
06/26 18:46,
1年前
, 45F
06/26 18:46, 45F
推
06/26 19:18,
1年前
, 46F
06/26 19:18, 46F
→
06/26 19:18,
1年前
, 47F
06/26 19:18, 47F
→
06/26 19:18,
1年前
, 48F
06/26 19:18, 48F
推
06/26 19:32,
1年前
, 49F
06/26 19:32, 49F
推
06/26 20:15,
1年前
, 50F
06/26 20:15, 50F
推
06/26 21:10,
1年前
, 51F
06/26 21:10, 51F
推
06/26 21:20,
1年前
, 52F
06/26 21:20, 52F
推
06/26 22:08,
1年前
, 53F
06/26 22:08, 53F
推
06/26 23:25,
1年前
, 54F
06/26 23:25, 54F
推
06/26 23:36,
1年前
, 55F
06/26 23:36, 55F
推
06/26 23:52,
1年前
, 56F
06/26 23:52, 56F
→
06/26 23:52,
1年前
, 57F
06/26 23:52, 57F
推
06/27 00:46,
1年前
, 58F
06/27 00:46, 58F
推
06/27 01:29,
1年前
, 59F
06/27 01:29, 59F
推
06/27 07:20,
1年前
, 60F
06/27 07:20, 60F
推
06/27 07:32,
1年前
, 61F
06/27 07:32, 61F
推
06/27 08:25,
1年前
, 62F
06/27 08:25, 62F
→
06/27 08:25,
1年前
, 63F
06/27 08:25, 63F
推
06/27 09:18,
1年前
, 64F
06/27 09:18, 64F
推
06/27 10:08,
1年前
, 65F
06/27 10:08, 65F
推
06/27 10:45,
1年前
, 66F
06/27 10:45, 66F
推
06/27 12:19,
1年前
, 67F
06/27 12:19, 67F
推
06/27 12:20,
1年前
, 68F
06/27 12:20, 68F
推
06/27 12:41,
1年前
, 69F
06/27 12:41, 69F
推
06/27 14:30,
1年前
, 70F
06/27 14:30, 70F
推
06/27 15:57,
1年前
, 71F
06/27 15:57, 71F
推
06/27 17:15,
1年前
, 72F
06/27 17:15, 72F
→
06/27 23:14,
1年前
, 73F
06/27 23:14, 73F
推
06/27 23:22,
1年前
, 74F
06/27 23:22, 74F
推
06/27 23:51,
1年前
, 75F
06/27 23:51, 75F
推
06/27 23:59,
1年前
, 76F
06/27 23:59, 76F
推
06/28 00:51,
1年前
, 77F
06/28 00:51, 77F
推
06/28 01:04,
1年前
, 78F
06/28 01:04, 78F
推
06/28 02:16,
1年前
, 79F
06/28 02:16, 79F
推
06/28 04:24,
1年前
, 80F
06/28 04:24, 80F
→
06/28 04:26,
1年前
, 81F
06/28 04:26, 81F
推
06/28 08:29,
1年前
, 82F
06/28 08:29, 82F
推
06/28 08:51,
1年前
, 83F
06/28 08:51, 83F
推
06/28 10:14,
1年前
, 84F
06/28 10:14, 84F
推
06/28 12:32,
1年前
, 85F
06/28 12:32, 85F
推
06/28 17:42,
1年前
, 86F
06/28 17:42, 86F
推
06/29 10:32,
1年前
, 87F
06/29 10:32, 87F
推
06/29 15:05,
1年前
, 88F
06/29 15:05, 88F
推
06/30 00:03,
1年前
, 89F
06/30 00:03, 89F
推
07/01 02:09,
1年前
, 90F
07/01 02:09, 90F
推
07/01 13:03,
1年前
, 91F
07/01 13:03, 91F
推
07/01 19:26,
1年前
, 92F
07/01 19:26, 92F
推
07/02 01:32,
1年前
, 93F
07/02 01:32, 93F
推
07/02 15:09,
1年前
, 94F
07/02 15:09, 94F
推
07/02 18:33,
1年前
, 95F
07/02 18:33, 95F
推
07/04 09:15,
1年前
, 96F
07/04 09:15, 96F
討論串 (同標題文章)
完整討論串 (本文為第 7 之 7 篇):