各公司 API 接口设计观察

2022-04-13 18:21:34 +08:00
 rv54ntjwfm3ug8

测试过程

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

首页随便找了个接口:

POST https://www.youtube.com/youtubei/v1/att/get?key=<input>&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"
        }
      }
    ]
  }
}

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

POST https://accounts.google.com/ListAccounts

Requests:

listPages=?
authuser=?
pid=?

Success Case (HTTP 200):

["**",[["**",1,"**","**@gmail.com","https://**.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 官方模板风格的请求(路由大驼峰,参数小驼峰)

推特详情 API ,懒得截图了

GET https://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 ,结果都属于上面几种情况,因为过滤并检查是否有隐私信息麻烦就不贴了。

结论

5238 次点击
所在节点    程序员
28 条回复
yuxiu
2022-04-14 09:38:47 +08:00
google 返回长度为 0 的内容,这么反人类吗,直接设 204 不就好了
dayeye2006199
2022-04-14 11:54:09 +08:00
推荐 shopify 的 API ,文档清晰,风格一致: https://shopify.dev/api/admin-rest
ZSeptember
2022-04-14 13:19:26 +08:00
Shopify API 设计还行,但是有些 API 很难用。
可以参考 stripe 。

API 设计也是要看场景的,Open API ,比如 Shopify ,Stripe 这种,国外一定是 RESTful 的,状态码也是按规范的。
但是用户 API ,就并不一定了,因为 RESTful 表达能力有限。
freeup
2022-04-14 14:27:58 +08:00
其实昨天那个帖子我也看了 都没敢说话 怕被喷,。。我们系统就是 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 我也会有这段逻辑

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

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

如果看完你不认同这个 一定淡定 淡定 不要喷我。。。。。
2kCS5c0b0ITXE5k2
2022-04-14 15:05:47 +08:00
用啥都可以. 把文档写好就行.
jjwjiang
2022-04-14 15:14:27 +08:00
建议看看 github 的
gmywq0392
2022-04-14 18:01:18 +08:00
看 Stripe 和 Deutsche Bank
pigspy
2022-04-15 09:21:23 +08:00
这跟崇洋媚外太大关系,就纯粹是有些(脏话)原教旨主义者扯着外国人的大旗来规训国内码农了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/846785

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX