测试过程
因为我的两个帖子 /t/838609 /t/846741 V 友们的意见都不太统一,刚好看到今天有人又在争论这个问题,于是我打算看看各公司 API 的接口设计

YouTube

首页随便找了个接口:
POST www.youtube.com/youtubei/v1/att/get?key=&prettyPrint=true
Request:
key=?
prettyPrint=?

Success Case (HTTP 200):
{
"responseContext": {
"serviceTrackingParams": [
{
"service": "**",
"params": [
{
"key": "**",
"value": "WEB"
},
{
"key": "**",
"value": "**"
},
]
},
**
],
"mainAppWebResponseContext": {
"datasyncId": "**",
"loggedOut": false
},
"webResponseContextExtensionData": {
"hasDecorated": true
}
},
"challenge": "**",
"botguardData": {
"program": "**",
"interpreterSafeUrl": {
"privateDoNotAccessOrElseTrustedResourceUrlWrappedValue": "//www.google.com/js/**.js"
}
}
}

Fail Case (不传 Key 字段 HTTP 403 ):
{
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"errors": [
{
"message": "The request is missing a valid API key.",
"domain": "global",
"reason": "forbidden"
}
],
"status": "PERMISSION_DENIED"
}
}

Fail Case 2 ( Key 随便传了个 0 HTTP 400 ):
{
"error": {
"code": 400,
"message": "API key not valid. Please pass a valid API key.",
"errors": [
{
"message": "API key not valid. Please pass a valid API key.",
"domain": "global",
"reason": "badRequest"
}
],
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "API_KEY_INVALID",
"domain": "googleapis.com",
"metadata": {
"service": "**.googleapis.com"
}
}
]
}
}

Gmail

大部分 API 都有混淆,选一个列登录 Google 账号列表的

POST accounts.google.com/ListAccounts
Requests:
listPages=?
authuser=?
pid=?

Success Case (HTTP 200):
["",[["",1,"","@gmail.com"," .googleusercontent.com/.jpg",0,0,1,null,1,"",null,]]]
Success Case 2 (清空 Cookies 后测试 HTTP 200):
返回长度 0 的内容。
Fail Case (listPages 传负数 HTTP 400 ):
返回长度 0 的内容。
另外这里看到了 3 个 ASP.NET Core 官方模板风格的请求(路由大驼峰,参数小驼峰)

Twitter:

推特详情 API ,懒得截图了
GET twitter.com/i/api/graphql/**/TweetDetail
Request:
variables=%7B%22focalTweetId%**
URL 解码后:
{"focalTweetId":"","referrer":"home",
Success Case (HTTP 200):
{
"data": {
"threaded_conversation_with_injections_v2": {
"instructions": [
{
"type": "TimelineAddEntries",
"entries": [
{
"entryId": "**"
**

Fail Case (随便破坏 JSON 结构几个字符 HTTP 400 )
{"errors":[{"message":"Cannot parse variables: \"focalTweetId\\"**

Fail Case 2 (传不存在的推特 ID HTTP 200 )
{"errors":[{"message":"_Missing: No status found with that ID.","locations":[{"line":5,"column":3}],

后续我又测试了 Amazon ,Azure ,AT&T 的 API ,结果都属于上面几种情况,因为过滤并检查是否有隐私信息麻烦就不贴了。
结论

奇怪 发出来格式乱了 结论也丢了

结论:

  1. 所测国外大公司同一产品的 API 路由都没有统一格式,链接中包含大小写的居多
  2. 所测公司 API 路由在成功状态下返回内容中都没有成功标识
  3. 国外公司对能处理的非输入错误返回 200 和 40x 的各占一半,输入错误全部为 40x
  4. 所以怎么用舒服怎么来就好
  5. V 站的 Markdown 编辑器好难用(逃)

google 的 api 设计是非常混乱的。。想学 api 设计不要学 google.

实际上大公司都是跨部门(甚至跨公司)、跨历史长流,API 混乱再正常不过了。

隔壁楼里支持用状态码已经是崇洋媚外了吗🐶

国内主流都是成功和失败返回的格式统一,这种不统一的不方便解析吧?

不同的产品,团队人员都不一样,语言也不一样,最关键的是历史都不一样。YouTube 是 Python 开始的,Facebook 是 java 开始的,你这些都要考虑

一般要考虑就考虑某一个产品的统一输出,像 aws ,azure ,Facebook ,Dropbox ,Twitter ,GitHub 的开放 api 之类的就比较标准和规范

p.s. 成功状态下内容中没有 code 和 message 我觉得更合理一些,不知道国内怎么养成个啥都需要的习惯。。

根据我的实际体验:
海外产品的 api 十分简洁甚至十分简单
大陆产品的 api 十分复杂甚至十分难用
其实就跟 App 一个德行

是不是又有舔狗鼓吹国外月亮比较圆了?

API 接多了,就觉得还是有 SDK 的香,不用自己接的才是最好的

刚看帖子,有人因为国内很多人把 code 放在 body 里面,解读成这个国家 xxxx
大受震撼

我比较欣赏 GitHub 的 API ,也比较好套用到自己的理念上

就拿 facebook 的 Graph Api ,也是定义了自己的业务错误码的
developers.facebook.com/docs/graph-api/guides/error-handling

然后的是 twitter ads api
developer.twitter.com/en/docs/twitter-ads-api/response-codes

那些说只有国内才这样做,国内风气不好的,真的有去了解过国外的 api 设计吗?

Error responses are served with a non-200-series HTTP code. 许愿帮你翻译吗?

只能说接触多的都是国外比较好的东西,做的不好的也基本接触不到,幸存者偏差了

做广告买量分析,对接过 facebook ,twitter ,google ,tiktok 的 ads api ,我觉得 Facebook 的 graph 是这里面做得最好的一个了

个人觉得 PayPal 的 API 很好,非常 restful ,返回里会有 HATEOAS link.例如 developer.paypal.com/docs/api/orders/v2/#orders_create

网上有好多聚合了好多个第三方支付平台的开源项目,用起来真的方便,统一的参数配置、初始化、调用接口;不同的参数字段名称、金额单位、加签算法等等都转换封装好了😂,设计模式用的很 6……有的把依赖安装方式都打好了,美滋滋,用完扫码支付几块钱再感谢作者

劳烦推荐一个,借鉴学习一下

1 、越是大厂,其接口风格就越混乱。员工上万,妖魔鬼怪。
2 、国外的代码也未必就比国内香。不幸接触过诺基亚、爱立信、摩托罗拉的代码,绝对是屎山中的珠穆朗玛。所以在某种意义上,这 3 家的倒掉也不是没有底层原因的。为了能持续摸鱼,代码还是要好好写,不然鱼塘干掉就尴尬了。
3 、接口风格最重要的不是 http 状态码 200 还是非 200 ,而是统一。当然我站 200 。如果非 200 ,body 可以直接返回数据,无需封装成统一的数据格式。200 的话,就必须有一致的封装,不然让前端怎么解码?
4 、200 一把梭的,是把 http 当传输协议用了,话说 http 本来就是传输协议啊。这。。。没毛病啊。

我觉得用 http 状态码,还是 200 一把梭都不是问题
只要能保证一致就好了,不要这个接口这样定义,那个接口又那样定义

google 返回长度为 0 的内容,这么反人类吗,直接设 204 不就好了

推荐 shopify 的 API ,文档清晰,风格一致: shopify.dev/api/admin-rest

Shopify API 设计还行,但是有些 API 很难用。
可以参考 stripe 。

API 设计也是要看场景的,Open API ,比如 Shopify ,Stripe 这种,国外一定是 RESTful 的,状态码也是按规范的。
但是用户 API ,就并不一定了,因为 RESTful 表达能力有限。

其实昨天那个帖子我也看了 都没敢说话 怕被喷,。。我们系统就是 get post ,只要进行了业务代码一定返回的 200,返回固定的格式
{"code","","msg":"","data":""}
我也是个实在派,感觉 api 是给开发人员用的,在都能满足功能且扩展性都差不多的情况下,我会优先选择简洁的方案。

1.我们只是把 http 当做一个传输协议,不参与任何业务逻辑,所有业务信息都已接口返回的内容为准,统一口径,这点就和 tcp/ip 一样,返回的包里才是具体的业务数据,就和虽然 tcp/ip 预留了可自定义的数据位置,但实际情况几乎不会有人去使用这个(不要杠 http 协议和 tcp 协议不再一层。。。我只是举个例子,非完全严谨,,瑟瑟发抖。。)

2.比如我们系统是前后端分离,外部传入的数据都要做防御性校验,比如参数必填,有错误,逻辑校验不过的情况,在我看来都是参数验证不过,返回一个固定的业务码,再返回一个实际具体的错误

3.我也对接过很多大厂的 api 某度 某宝 某信 尤其支付这块,业务情况实在是太多,如果不使用自定义的业务码,只返回错误 msg 不论是提工单还是检索问题,或者系统内部进行错误判定都不是太合适,假设是 http 状态码+错误 msg 那么在 http 码非 200 的情况下 就只能通过字符串消息进行错误判定,这样总感觉给人一种不严谨的感觉,因为错误码不会变,但是具体的错误文案可是会变得

4.200 一把梭 前端拦截也比较简单,只需要拦截非 200 且错误码不是成功的就行,也就是先 http 状态拦截,再 code 的拦截,只要返回 200 就能保证这个请求一定是到了业务里,其他情况一定就是出在了 http 协议上

5.而且返回具体的业务码可以前端可以根据不同的错误码 进行业务处理,例如:登录时账号密码错误 返回 1 那超过 5 次返回 2 那前端就会给出个提示 60 秒后在尝试,这种业务控制。当然这个功能不依赖后端也能完成,但是当这个逻辑作为业务的硬性逻辑时 那必须就得由后端控制,即使你直接访问 api 我也会有这段逻辑

以上仅是我们系统是这样做的,不代表任何群体,任何观点,我只是陈述我们系统是怎么做的而已。。。

存在即合理,没有绝对的正确与绝对的错误,没有最好的设计,只有最合适的设计。。。。。

如果看完你不认同这个 一定淡定 淡定 不要喷我。。。。。

用啥都可以. 把文档写好就行.

建议看看 github 的

看 Stripe 和 Deutsche Bank

这跟崇洋媚外太大关系,就纯粹是有些(脏话)原教旨主义者扯着外国人的大旗来规训国内码农了