作者Hsins (迅雷不及掩耳盗铃)
看板Soft_Job
标题Re: [讨论] API没资料,回200还是404比较好
时间Sat Jun 25 23:48:07 2022
这篇就不以引述的方式回覆了,因为算是对
後续其他人不论在推文中或是回文中的内容
回覆,另外也是针对我自己在前一篇文章中
没有提到的部分进行说明。
(1) 叙述问题与回答问题
我不知道这里有多少人上过 jserv的课,如
果有的话,他会频频强调不要「举烛」。从
推文和回文中可以看到,其实不论是发文者
还是回答者,似乎并没有很正视这个问题…
…
回到最一开始的问题:
「API 没资料要回传 200 还是 404?」
‧什麽样的 API 呢?
‧什麽样的场景下设计的呢?
‧什麽样的状况叫做没资料?
‧有没有基於什麽规范或风格?
‧调用的人是谁?
‧你怎麽想的呢?
如果没有叙述清楚,要人怎麽回答呢?我想
分享一下两段文字:
https://i.imgur.com/JWMQJjn.png
[来源] http://hhp.li/4aq287
https://i.imgur.com/KPxidqA.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://webptt.com/cn.aspx?n=bbs/Soft_Job/M.1656172096.A.5AE.html
1F:推 sssyoyo: 优文推,学到不少,谢谢 06/25 23:53
2F:推 lasekoutkast: 推 06/26 00:13
3F:推 WulinWorks: 推 06/26 00:51
4F:推 jackblack: 推 06/26 00:53
5F:推 bill0205: 推 06/26 01:33
6F:推 ss8651twtw: 推 06/26 01:47
7F:推 devilkool: 感谢优文 06/26 01:56
8F:推 LeoSW: 推问问题的方式 06/26 06:52
9F:推 bjk: 11 06/26 06:57
10F:推 nh60211as: 优文 06/26 08:54
11F:推 yehzu: 真是优文…大推 06/26 09:46
12F:推 TAKADO: 推, It depends <- 这一句很有用 06/26 09:57
13F:推 windclara: 推推! 06/26 10:00
14F:推 wahaha279: 推 06/26 10:16
15F:推 toxic541224: 推 06/26 10:17
16F:推 yoshonabee: 优文推 06/26 10:31
17F:推 lovdkkkk: 推第一点跟那两张图 QQ 06/26 11:10
18F:推 as23041248: 这种思维很棒,透过问自己各种问题,考虑自己所在环 06/26 11:18
19F:→ as23041248: 境的状况,厘清自己到底在做什麽,才开始蒐集资料, 06/26 11:18
20F:→ as23041248: 参考别人作法,解决问题。有时候直接想解决问题忽略 06/26 11:18
21F:→ as23041248: 掉前提,也是我常犯的毛病,感谢文章给我的提醒 06/26 11:18
22F:推 Arctica: 感谢 舒服 06/26 12:32
23F:推 lovdkkkk: 不过新创那段,刚巧我目前在新创,工程最近刚由 2 人增 06/26 12:54
24F:→ lovdkkkk: 加到 3 人,倒是有 Unit/Api/E2E 测试,及 push 後自动 06/26 12:55
25F:→ lovdkkkk: 测试与部署,不过测试只针对重点,覆盖率极低 XDD 06/26 12:56
26F:推 kuan: 推 06/26 13:54
27F:推 steven95421: 推 06/26 14:02
28F:推 moszap: 推 06/26 14:10
29F:推 TheWhack: 我是觉得"问题"本身也可以不断refine XD 06/26 14:25
30F:推 ppoozine: 推 06/26 14:32
31F:推 Y78: 推 06/26 14:34
32F:推 ccnancy: 推 06/26 15:02
33F:推 sky80420: 推 06/26 15:19
34F:推 ian90911: 感谢分享 06/26 15:42
35F:推 yc86209: 推 06/26 15:57
36F:推 stu87616: 感谢这串让我知道很多 IT 不懂 Rest 也在写 API 06/26 16:28
37F:推 CRPKT: 测试测到重点其实也比覆盖率重要呀 06/26 16:44
38F:推 iamOsaka: 推 06/26 17:03
39F:推 mTwTm: 非常完整 06/26 17:04
40F:推 Rmustang: 推 06/26 17:10
41F:推 pttano: 你是不是吃到jserv 口水,回文的style 这麽像 06/26 17:13
42F:推 drajan: 所以有人才会说提出够好的问题 答案也出来一半了 就是这个 06/26 17:34
43F:→ drajan: 意思 「提问」是科学精神的重要一环啊 工程师们 06/26 17:34
44F:推 NTUTM04: 推,整篇的回答很有条理且易理解 06/26 18:09
45F:推 APTON: 06/26 18:46
46F:推 waterwalk: 问问题是个学问 前阵子也看到stack overflow神人 06/26 19:18
47F:→ waterwalk: 也有写书说 怎麽样问问题最合适(就是辣个C#神人) 06/26 19:18
48F:→ waterwalk: 他写的code如果编译不过 编译器要道歉的辣个人 06/26 19:18
49F:推 Belieeve: 推推Hsins大,回答得好完整 06/26 19:32
50F:推 zxc8787: 推 06/26 20:15
51F:推 sharek: 推详细补充 06/26 21:10
52F:推 windmax1: 好文必须推 06/26 21:20
53F:推 lofiktb: 优文推 06/26 22:08
54F:推 kasimEnix: 推,真心感谢 06/26 23:25
55F:推 hsnusonic: 好文推 06/26 23:36
56F:推 viper9709: 这问题本来就跟实际的状况有关 06/26 23:52
57F:→ viper9709: 原po没讲的大家当然各自发挥XD 06/26 23:52
58F:推 endless1999: 推 06/27 00:46
59F:推 mirror0227: PTT充满大神 06/27 01:29
60F:推 aa0983163178: 推 06/27 07:20
61F:推 tay2510: 推!好文 06/27 07:32
62F:推 justaID: 推好文,前面的提问思维,和後面的style分析都很值得思 06/27 08:25
63F:→ justaID: 考,尤其开头的提问思维让我想到经典的客户需求秋千漫画 06/27 08:25
64F:推 tomap41017: 推,这才是思考方式。 06/27 09:18
65F:推 ae86357961: 推,受益良多 06/27 10:08
66F:推 chatnoir: 好文不M吗? 06/27 10:45
67F:推 zxc6414189: 推 06/27 12:19
68F:推 stiiveo: 优质好文! 06/27 12:20
69F:推 lairx: 推 06/27 12:41
70F:推 whatzup1124: 推 06/27 14:30
71F:推 Tube: 推 06/27 15:57
72F:推 jackflu: 好扯,太精彩了吧,开头分享的文章也很具有启发性 06/27 17:15
73F:→ peter98: 今年跳槽Amazon就是香 香爆 06/27 23:14
74F:推 zzzzzz6666: 推 06/27 23:22
75F:推 MissPigHead: 推,谢谢 06/27 23:51
76F:推 tenpoinyuki: 推 06/27 23:59
77F:推 loxyz: 推。 小瑕疵 Android <==> iOS; Kotlin <==> Swift 06/28 00:51
78F:推 kop14922000: 推 06/28 01:04
79F:推 tw11509: 推 06/28 02:16
80F:推 kingofsdtw: 安全性我一律回答404 06/28 04:24
81F:→ kingofsdtw: 只有debug才开 return200 加 debug讯息 06/28 04:26
82F:推 tinuo: 推一个,带出很多观点 06/28 08:29
83F:推 A1ch3mi5t: 推 06/28 08:51
84F:推 zxcchiou: 推 谢谢学到了 06/28 10:14
85F:推 zegas: 推 06/28 12:32
86F:推 Kenqr: 推 06/28 17:42
87F:推 Sunal: 完全没想到 DevOps/SRE 的观点,404确实是很好判断的依据 06/29 10:32
88F:推 kira518: 推 06/29 15:05
89F:推 corahoda: 推 06/30 00:03
90F:推 MangoTW: 这一串只推这一篇 见解卓越且点出正确的思考方向 07/01 02:09
91F:推 air4028: 好文 推 07/01 13:03
92F:推 Gwendolynn: 推推 07/01 19:26
93F:推 www54500: 推 07/02 01:32
94F:推 EJLin: 完整优文推 07/02 15:09
95F:推 adminc: 推 07/02 18:33
96F:推 j606888: 优质文推推 07/04 09:15