V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rv54ntjwfm3ug8
V2EX  ›  程序员

各公司 API 接口设计观察

  •  3
     
  •   rv54ntjwfm3ug8 · 171 天前 · 3760 次点击
    这是一个创建于 171 天前的主题,其中的信息可能已经有所发展或是发生改变。

    测试过程

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

    • YouTube

    首页随便找了个接口:

    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"
            }
          }
        ]
      }
    }
    
    • Gmail

    大部分 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 官方模板风格的请求(路由大驼峰,参数小驼峰)

    • Twitter:

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

    结论

    28 条回复    2022-04-15 09:21:23 +08:00
    rv54ntjwfm3ug8
        1
    rv54ntjwfm3ug8  
    OP
       171 天前
    奇怪 发出来格式乱了 结论也丢了

    结论:
    1. 所测国外大公司同一产品的 API 路由都没有统一格式,链接中包含大小写的居多
    2. 所测公司 API 路由在成功状态下返回内容中都没有成功标识
    3. 国外公司对能处理的非输入错误返回 200 和 40x 的各占一半,输入错误全部为 40x
    4. 所以怎么用舒服怎么来就好
    5. V 站的 Markdown 编辑器好难用(逃)
    golangLover
        2
    golangLover  
       171 天前 via Android
    google 的 api 设计是非常混乱的。。想学 api 设计不要学 google.
    maichael
        3
    maichael  
       171 天前
    实际上大公司都是跨部门(甚至跨公司)、跨历史长流,API 混乱再正常不过了。
    agagega
        4
    agagega  
       171 天前 via iPhone
    隔壁楼里支持用状态码已经是崇洋媚外了吗🐶
    Soin
        5
    Soin  
       171 天前
    国内主流都是成功和失败返回的格式统一,这种不统一的不方便解析吧?
    freefcw
        6
    freefcw  
       171 天前   ❤️ 2
    不同的产品,团队人员都不一样,语言也不一样,最关键的是历史都不一样。YouTube 是 Python 开始的,Facebook 是 java 开始的,你这些都要考虑

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

    p.s. 成功状态下内容中没有 code 和 message 我觉得更合理一些,不知道国内怎么养成个啥都需要的习惯。。
    Building
        7
    Building  
       171 天前 via iPhone
    根据我的实际体验:
    海外产品的 api 十分简洁甚至十分简单
    大陆产品的 api 十分复杂甚至十分难用
    其实就跟 App 一个德行
    afewok
        8
    afewok  
       171 天前   ❤️ 2
    是不是又有舔狗鼓吹国外月亮比较圆了?
    chendy
        9
    chendy  
       171 天前   ❤️ 2
    API 接多了,就觉得还是有 SDK 的香,不用自己接的才是最好的
    liuidetmks
        10
    liuidetmks  
       171 天前 via iPhone
    @afewok 刚看帖子,有人因为国内很多人把 code 放在 body 里面,解读成这个国家 xxxx
    大受震撼
    hu8245
        11
    hu8245  
       171 天前
    我比较欣赏 GitHub 的 API ,也比较好套用到自己的理念上
    Goooooos
        12
    Goooooos  
       171 天前
    就拿 facebook 的 Graph Api ,也是定义了自己的业务错误码的
    https://developers.facebook.com/docs/graph-api/guides/error-handling


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

    那些说只有国内才这样做,国内风气不好的,真的有去了解过国外的 api 设计吗?
    binux
        13
    binux  
       171 天前
    @Goooooos Error responses are served with a non-200-series HTTP code. 许愿帮你翻译吗?
    chendy
        14
    chendy  
       171 天前
    @Goooooos 只能说接触多的都是国外比较好的东西,做的不好的也基本接触不到,幸存者偏差了
    Goooooos
        15
    Goooooos  
       171 天前
    @chendy 做广告买量分析,对接过 facebook ,twitter ,google ,tiktok 的 ads api ,我觉得 Facebook 的 graph 是这里面做得最好的一个了
    kakach
        16
    kakach  
       171 天前 via Android
    个人觉得 PayPal 的 API 很好,非常 restful ,返回里会有 HATEOAS link.例如 https://developer.paypal.com/docs/api/orders/v2/#orders_create
    lower
        17
    lower  
       171 天前
    @chendy 网上有好多聚合了好多个第三方支付平台的开源项目,用起来真的方便,统一的参数配置、初始化、调用接口;不同的参数字段名称、金额单位、加签算法等等都转换封装好了😂,设计模式用的很 6……有的把依赖安装方式都打好了,美滋滋,用完扫码支付几块钱再感谢作者
    codeMore
        18
    codeMore  
       171 天前
    @lower 劳烦推荐一个,借鉴学习一下
    xuanbg
        19
    xuanbg  
       171 天前   ❤️ 1
    1 、越是大厂,其接口风格就越混乱。员工上万,妖魔鬼怪。
    2 、国外的代码也未必就比国内香。不幸接触过诺基亚、爱立信、摩托罗拉的代码,绝对是屎山中的珠穆朗玛。所以在某种意义上,这 3 家的倒掉也不是没有底层原因的。为了能持续摸鱼,代码还是要好好写,不然鱼塘干掉就尴尬了。
    3 、接口风格最重要的不是 http 状态码 200 还是非 200 ,而是统一。当然我站 200 。如果非 200 ,body 可以直接返回数据,无需封装成统一的数据格式。200 的话,就必须有一致的封装,不然让前端怎么解码?
    4 、200 一把梭的,是把 http 当传输协议用了,话说 http 本来就是传输协议啊。这。。。没毛病啊。
    Goooooos
        20
    Goooooos  
       171 天前
    我觉得用 http 状态码,还是 200 一把梭都不是问题
    只要能保证一致就好了,不要这个接口这样定义,那个接口又那样定义
    yuxiu
        21
    yuxiu  
       171 天前
    google 返回长度为 0 的内容,这么反人类吗,直接设 204 不就好了
    dayeye2006199
        22
    dayeye2006199  
       171 天前
    推荐 shopify 的 API ,文档清晰,风格一致: https://shopify.dev/api/admin-rest
    ZSeptember
        23
    ZSeptember  
       171 天前
    Shopify API 设计还行,但是有些 API 很难用。
    可以参考 stripe 。

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

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

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

    如果看完你不认同这个 一定淡定 淡定 不要喷我。。。。。
    emeab
        25
    emeab  
       171 天前
    用啥都可以. 把文档写好就行.
    jjwjiang
        26
    jjwjiang  
       171 天前
    建议看看 github 的
    gmywq0392
        27
    gmywq0392  
       170 天前
    看 Stripe 和 Deutsche Bank
    pigspy
        28
    pigspy  
       170 天前
    这跟崇洋媚外太大关系,就纯粹是有些(脏话)原教旨主义者扯着外国人的大旗来规训国内码农了
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2074 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 301ms · UTC 07:24 · PVG 15:24 · LAX 00:24 · JFK 03:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.