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

优秀的 REST API 设计指南

  •  1
     
  •   KalaSearch · 2020-07-29 06:14:50 +08:00 · 26128 次点击
    这是一个创建于 1582 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这是一篇会长期更新的文章

    什么样的 API 设计能被称为优秀当然是一个非常主观的标准,但是还是有一些客观可考量 API 质量的数据,比如

    1. 接了你设计的 API 的前端给好评的比例是多少,还是边接边骂
    2. 如果你的 API 本身就是你的产品的话(比如 Stripe,Algolia 或者 Github 等等),你的用户会对你的 API 好评吗
    3. API 是不是一读即可以清晰地知道,对应接口是做什么的。换句话说,接入 API 时需要的交流时间成本有多高

    不管是前端程序员还是后端程序员,都少不了跟 API 打交道。后端需要把 API 设计和实现出来,而前端程序员需要把界面逻辑和 API 接起来,因此对于 REST 的设计规则有一些基本了解,不管你是前端还是后端,都会有很大帮助。

    之前在厂里设计了一些还算被广泛使用的 API, 因此我写了这篇文章,结合之前的经验总结了一些要点。希望作为一个参考,可以帮助大家

    文章请戳 => 优秀的 REST API 设计指南

    当然我想要说明的是,设计 API 在一定范围内是有规律可循的,但是太过抠细节则会陷入无穷无尽地“宗教版”争论中,所以请大家理论讨论。

    你们设计 API 的时候有些什么原则?有哪些好的规范和经验可以介绍和分享给大家?欢迎告诉我,我会加到文章中

    98 条回复    2021-03-09 12:22:47 +08:00
    abbycin
        2
    abbycin  
       2020-07-29 07:24:49 +08:00 via Android   ❤️ 5
    我八股文写得特别好
    baiyi
        3
    baiyi  
       2020-07-29 07:30:25 +08:00   ❤️ 2
    我认为在设计过程中,需要考虑 HTTP 方法的幂等性。比如 Github 的 Star 操作,为什么是 PUT 而不是 POST,就是从幂等性方面考虑的
    KallyDev
        4
    KallyDev  
       2020-07-29 07:31:05 +08:00 via iPhone   ❤️ 19
    补充一个微软在 GitHub 公开的规范,非常详细

    https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md
    shijianit
        5
    shijianit  
       2020-07-29 08:21:40 +08:00
    如果要接口全部加密,get 方式请求,不是会暴露出来 id 数据吗?
    xuanbg
        6
    xuanbg  
       2020-07-29 08:22:37 +08:00
    修改密码和重置密码怎么设计?软删和硬删同时存在怎么办?
    xuanbg
        7
    xuanbg  
       2020-07-29 08:23:09 +08:00
    @shijianit 所以 id 不要用自增
    bsg1992
        8
    bsg1992  
       2020-07-29 08:43:48 +08:00   ❤️ 1
    这种只适合对外的 api 并且功能单一
    一个 ERP 查询几十个字段你用 get?
    gnozix
        9
    gnozix  
       2020-07-29 08:51:17 +08:00
    想问问下载接口应该怎么设计
    gowk
        10
    gowk  
       2020-07-29 09:08:48 +08:00   ❤️ 2
    @bsg1992 人家说的是在卡拉搜索的业务背景下,设计优秀 API 的最佳实践,你非要拿 ERP 来杠,有意思么
    nockyQ
        11
    nockyQ  
       2020-07-29 09:12:50 +08:00
    关于版本划分这一块,除了常见的 URI 版本控制之外还有其他两种。
    https://restfulapi.net/versioning/
    感觉楼主可以在这个基础上展开聊一聊。
    lolizeppelin
        12
    lolizeppelin  
       2020-07-29 09:36:29 +08:00   ❤️ 1
    paypal api 和沙箱比微信支付漂亮太多了

    但是不妨碍 paypal 垃圾微信支付好用......
    KalaSearch
        13
    KalaSearch  
    OP
       2020-07-29 09:46:01 +08:00
    @nockyQ 啊是的,stripe 用的是这种。感谢你的新信息
    KalaSearch
        14
    KalaSearch  
    OP
       2020-07-29 09:46:30 +08:00
    @baiyi 感谢 <3
    KalaSearch
        15
    KalaSearch  
    OP
       2020-07-29 09:46:48 +08:00
    @KallyDev 这个很赞,我之前也看过,谢谢提出来,我会加到文章里
    KalaSearch
        16
    KalaSearch  
    OP
       2020-07-29 09:47:56 +08:00
    @shijianit id 应该默认认为已经暴露,藏不住。楼下说的用 uuid 是个好办法,不过不管怎么样不应该认为 id 可以隐藏起来达到安全的目的。(安全我懂得不多,更详细等楼下们讨论啦)
    KalaSearch
        17
    KalaSearch  
    OP
       2020-07-29 09:48:35 +08:00
    @gnozix 能说说具体场景吗?文件下载?
    wellsc
        18
    wellsc  
       2020-07-29 09:53:32 +08:00
    restfool (逃
    MrTreasure
        19
    MrTreasure  
       2020-07-29 10:25:34 +08:00
    还是缺乏具体场景,文中的内容就是是属于 restful 的标准。但是对于难点没有很好的讲解,比如 restful 如何返回错误。区分 HTTP 错误以及业务错误
    ZacksT
        20
    ZacksT  
       2020-07-29 10:58:18 +08:00   ❤️ 2
    你的 REST API 满足公司 /研发团队标准就是好的设计。接口标准可以帮助开发者规避(公司研发 /团队研发)遇见过的问题或可能遇到的问题,也可以让组内代码标准化,统一化。

    就拿一个简单的例子,一个分页查询的接口。其包含分页条件与不定量的查询条件。
    你可以通过 GET 方式请求,将参数定义在 url 上。也可以通过 POST 方式请求,将查询参数定义在 requestbody 里。
    第一个方式,在遇到查询条件复杂的情况下,会导致 url 过长。
    第二种方式,又会产生很多 VO 的定义。
    采用混搭又让前后端代码变得混乱。

    我个人认为,只要满足团队要求的 API,就是好的 API 。具体实现各有好处,看团队取舍了
    KalaSearch
        21
    KalaSearch  
    OP
       2020-07-29 11:19:46 +08:00
    @ZacksT 感谢回复。是的,满足团队、客户需求就是好 API 。对于你说的参数定义的例子,GET + URL 参数挺好的,遵从 REST 语义



    @wellsc 不要淘气
    bsg1992
        22
    bsg1992  
       2020-07-29 11:42:31 +08:00
    @gowk 我并没有杠,你说回复也印证了我上面说的 [适合对外的 api 并且功能单一] r
    ibreaker
        23
    ibreaker  
       2020-07-29 11:57:46 +08:00   ❤️ 2
    小伙子很活跃啊,天天都能刷到你
    lovedebug
        24
    lovedebug  
       2020-07-29 12:40:40 +08:00
    @ZacksT 分页 GET 查询一般只带 limit 和 page,少量支持投影和过滤,如果有带其他复杂的 query 条件,其实更应该走 POST search 自定义方法
    ieiayaobb
        25
    ieiayaobb  
       2020-07-29 13:09:32 +08:00
    Get by Id 的比较明确,如果是 Get by name 这种,name 是唯一的怎么设计比较好?不想用 query 是因为不想在 name 不存在的时候返回空数组,而是希望也能和 Get by id 一样返回 404
    xjchenhao
        26
    xjchenhao  
       2020-07-29 16:27:06 +08:00
    修改密码和重置密码,逼死强迫症😂
    xjchenhao
        27
    xjchenhao  
       2020-07-29 16:27:42 +08:00   ❤️ 1
    @xuanbg 修改密码和重置密码,逼死强迫症😂
    grzhan
        28
    grzhan  
       2020-07-29 17:27:59 +08:00   ❤️ 5
    之前负责撰写公司的 API 规范,当时也参考了很多包括 Azure ( https://docs.microsoft.com/zh-cn/azure/architecture/best-practices/api-design )、Google Cloud ( https://cloud.google.com/apis/design/ )等公司的规范,大厂的标准往往更加规范,给人很多对于 API 设计上概念理解的启发。

    其中感觉最详细的大概是 Zalendo 的: https://opensource.zalando.com/restful-api-guidelines/ ,其中有非常多的实践是可以参考的,也像 RFC 一样规范了 MUST 、SHOULD 、MAY 的遵守分级。

    关于文中提到的 REST 表示一个动作,我们参考的更多是 ElasticSearch API 的做法,即将动词加上下划线前缀,作为 POST 方法进行服务,形如: http://cloud.sy/machine/xxxx/_restart

    关于这一块 Google API 是用冒号作为前缀的,但一些路由框架会占用冒号作为关键字,因此考虑使用下划线代替。
    gnozix
        29
    gnozix  
       2020-07-29 18:01:56 +08:00
    @KalaSearch 对前台展示的表格数据,以 excel 的格式进行下载;所以需要下载的比较多。感觉 REST 风格不太容易表示需要下载的资源
    wshcdr
        30
    wshcdr  
       2020-07-29 19:10:54 +08:00
    值得看一下
    Heanes
        31
    Heanes  
       2020-07-29 19:16:17 +08:00
    同意 8 楼,系统内部交互可能还是“常规”的设计形式
    lovedebug
        32
    lovedebug  
       2020-07-30 00:06:28 +08:00   ❤️ 1
    @grzhan 同负责撰写 API 规范,其实关于 list 操作的 filter 功能,在实际 API 设计中有些疑惑使用场景,因为大部分情况下使用一般的 query parameter 就可以解决。我的理解是一般的 query parameter 默认是 and 操作,缺乏 or 操作以及 range value 等功能,而 $filter 主要在 url 中描述若干参数复杂的逻辑运算,如果这么做用 POST 自定义动作不是更好吗?想听一下你的理解。
    xuanbg
        33
    xuanbg  
       2020-07-30 08:46:07 +08:00
    @lovedebug 要是支持复杂的 or 和 and 条件组合,url 参数就丑的要死了……不信的可以看 kibana
    szthanatos
        34
    szthanatos  
       2020-07-30 09:01:18 +08:00 via Android
    批量操作的实践为什么很少有人谈←_←
    solee
        35
    solee  
       2020-07-30 09:10:45 +08:00
    经过几年的实践,我们最后全部统一了用 POST,之前看过一篇亚马逊写的关于 Restful API 设计的改进,加入动词的描述,感觉更合理
    lovedebug
        36
    lovedebug  
       2020-07-30 09:42:19 +08:00
    @szthanatos 微软规范有谈的
    lovedebug
        37
    lovedebug  
       2020-07-30 09:43:30 +08:00
    @xuanbg 哈哈 跟业务场景有关,如果不想用万能 POST,可能只能在 url query 中支持一些 or 查询,客户在使用我们的 public api 时提出的
    lovedebug
        38
    lovedebug  
       2020-07-30 09:47:42 +08:00
    @solee 自定义动词应该在已有的 RESTful 规范不满足时候才使用
    Nolink
        39
    Nolink  
       2020-07-30 09:58:50 +08:00
    收藏了,谢谢分享
    ericls
        40
    ericls  
       2020-07-30 10:11:56 +08:00 via iPhone
    用现成的 query language 不好吗? 非要把 http headers 滥用成 query 还要自己定义 实现 维护……
    Amit
        41
    Amit  
       2020-07-30 10:52:53 +08:00   ❤️ 2
    @xuanbg
    密码一般都是要做 hash 的,且不能暴露给前端,所以需要对这个字段单独修改,而不能放到完整信息中修改并返回,修改密码是在登录状态下,所以我会设计为 PUT /v1/users/{id}/password (管理员修改用户密码)或 PUT /v1/users/self/password (修改自己的密码),重置密码我理解为非登录状态下修改密码(不确定用户身份),所以我会设计为 PUT /v1/users/password,然后再 body 中提供用户名、验证码等信息。

    软删除也是删除,对应用来说如果删除了就是不存在的,应用中不应该能看到,软删除和物理删除同时存在是不合理的,这种情况应该设计一个状态字段区分,而不是使用逻辑删除。
    xuanbg
        42
    xuanbg  
       2020-07-30 12:01:16 +08:00   ❤️ 1
    @Amit
    修改密码和重置密码我也是一样的处理。在复数形式的资源后面,有时候不但要加动词,还得加属性,以定位到更细一层的资源才行。

    我说的软删其实是禁用,只是为了理解方便。业务前端看不到了,也就没得用了。但元数据管理后端应该能看到,毕竟禁用后说不得还会启用。。。硬删当然就是数据灰灰,再也无法恢复的。如果软删用 PUT:/v1/users,那就和修改姓名冲突了。我是这样规划的,修改普通属性 PUT:/v1/users,禁用 PUT:/v1/users/status,删除 DELETE:PUT:/v1/users 。
    jorneyr
        43
    jorneyr  
       2020-07-30 16:09:28 +08:00
    RESTful 在 URL 里是禁止使用动词的,但是很多时候有的 URL 中用动词来表达很自然,强制使用 RESTful 的风格的话会很难受
    imhxc
        44
    imhxc  
       2020-07-30 18:19:45 +08:00
    我一直有个问题,请教下。
    在实际业务中,各种需求都有,很难严格遵守 RESTful API,拿文章中的示例来说:

    GET /owners/1/pets/ 获取 id 为 1 的主人的所有宠物
    1. 如果区分角色怎么办,比如管理员获取 id 为 1 的主人的所有宠物,结果中包含所有状态的宠物;
    2. 其他人需要查看 id 为 1 的主人所有宠物,结果中只返回状态为「可公开」的宠物;

    这种怎么设计?
    codingbody
        45
    codingbody  
       2020-07-30 18:22:52 +08:00
    我有个问题问大家,为什么安全扫描的时候,不准我使用除了 GET 、POST 之外的请求,我认为请求的方式和安全没啥关系吧
    DeWhite
        46
    DeWhite  
       2020-07-30 18:59:43 +08:00
    那个就一句话,吃屎啦。就是没有主语的,国内的很明显主语省略的句子还有很多。
    xcstream
        47
    xcstream  
       2020-07-30 20:21:36 +08:00
    这标题隐含意思就是不 rest 就不优秀(狗头)
    KalaSearch
        48
    KalaSearch  
    OP
       2020-07-31 01:29:46 +08:00
    @imhxc 用 ACL 来控制,REST endpoint 没办法控制的
    KalaSearch
        49
    KalaSearch  
    OP
       2020-07-31 01:30:24 +08:00
    @DeWhite 你说的是祈使句,祈使句当然可以没有主语(省略了第二人称主语)
    forgaoqiang
        50
    forgaoqiang  
       2020-07-31 12:16:24 +08:00
    看了下 Discuz Q,真的几斤,完全的 RESTFUL 风格,patch delete 各种方法都用
    grzhan
        51
    grzhan  
       2020-07-31 13:46:45 +08:00   ❤️ 1
    @lovedebug 我个人觉得关于复杂查询不管是用 $filter 还是直接 POST 自定义方法(如 "_search" )都是可以的,具体看自己场景。
    事实上我们项目实际实践中,这种情况还是自定义 POST 方法用的比较多
    GavinZZ
        52
    GavinZZ  
       2020-07-31 13:52:12 +08:00
    ??
    GavinZZ
        53
    GavinZZ  
       2020-07-31 13:52:38 +08:00
    还有个叫车满满的。。。工资给开的还算可以 13K+ 14 薪,但是不推荐去,企业文化很奇葩
    lovedebug
        54
    lovedebug  
       2020-07-31 14:13:54 +08:00   ❤️ 1
    @grzhan 嗯。$filter 需要写 parser 专门处理,否则会重复造轮子
    grzhan
        55
    grzhan  
       2020-07-31 14:16:34 +08:00   ❤️ 2
    @lovedebug 如果查询场景需求确实很复杂的业务的话,我们会考虑上 GraphQL 的
    lovedebug
        56
    lovedebug  
       2020-07-31 14:20:31 +08:00   ❤️ 1
    @grzhan 主要是 GraphQL 对已有产品的 RESTful API 破坏性过大,ROI 也不够高,另外也考虑在微服务和 k8s 中 GraphQL 中心化并不是一个很完美的方案。其实主要的阻力是项目进度和同事。哈哈哈哈
    dongxiaoxian
        57
    dongxiaoxian  
       2020-07-31 15:09:26 +08:00
    好复杂
    ChanKc
        58
    ChanKc  
       2020-07-31 18:57:19 +08:00
    @codingbody 没有,但是历史上发生过一些 HTTP server 对 PUT,DELETE 等请求实现不当,导致远程代码执行等漏洞。一些公司就会觉得索性禁了这些请求更好
    yixinlove
        59
    yixinlove  
       2020-08-02 19:29:08 +08:00
    @KallyDev 好东西
    wangxiaoaer
        60
    wangxiaoaer  
       2020-08-03 09:23:35 +08:00
    这个帖子很有启发啊,顺便问一下,针对楼上一些老哥们提到的复杂的组合条件查询,如果是基于 spring boot + jpa 的应用,如何优雅的实现呢?
    cbasil
        61
    cbasil  
       2020-08-03 09:31:29 +08:00
    设计 API 的目的是为了前端好评? api 接口安全和效率都不需要考虑了吗?你去看看阿里,腾讯等大公司的接口文档,有几个是完全按照 REST API 来设计的。
    lovedebug
        62
    lovedebug  
       2020-08-03 09:53:26 +08:00   ❤️ 1
    @cbasil 一是对内为了公司内部统一,减少沟通成本。而是针对 public api 与主流统一,减少用户的集成成本。
    nig001
        63
    nig001  
       2020-08-03 14:43:53 +08:00
    不错的
    fy
        64
    fy  
       2020-08-04 01:38:35 +08:00   ❤️ 1
    @lovedebug #32

    这个我做了,默认 and 操作,请求类似这样:

    /api/topic/list/1?time.ge=1577808000&order=time.desc&select=id,title

    前端反馈一般,说是不好理解。语言是 python

    https://github.com/fy0/slim


    问题主要是几处:

    1. http header 有限,有的查询条件放不下,其实同时支持提交 body 查询更好些( get 提交 body 是规范允许的,只是很多 http server 选择不解析)

    2. 对查询的掌控力度不够。前端提交上来一个请求,说某种情况下希望将某个条件变成 or 查询,这时候做不到。当然这和 orm 还有底层实现有关,这是一个整体设计上的问题。

    3. 连表查询比较复杂。

    4. 全栈开发会觉得好用,有的纯前端就觉得这是后端偷懒。

    所以可能不光是规范问题,还是框架问题,甚至要连同 orm 、表单验证、权限之类做通盘考虑。

    @imhxc #44

    角色权限 + ACL
    sunzhenyucn
        65
    sunzhenyucn  
       2020-08-04 04:42:12 +08:00
    请让我默默地 mark 一下
    lovedebug
        66
    lovedebug  
       2020-08-04 09:35:07 +08:00
    @fy 感谢回复,是的,get 带参数会有这些问题。
    一般对于 simple collection items 的 list(GET 方法)操作,我建议用 order,filter, 这样语义清晰,主要实现集合过滤功能。可以尝试在 filter= X OR Y 这样的形式实现 or 操作
    我的理解是对于复杂集合(如 logs 等)或通用操作的模糊搜索还是用 POST + custom method,例如 /v1/items/search,除非可以细化复杂集合为若干简单的集合。
    主要这个度不好把握。
    当然,从实现简单程度来看,所有的 order,filter,projection 都可以定义为用 post 实现。
    thtznet
        67
    thtznet  
       2020-08-04 11:15:03 +08:00
    看到 API 和表对应,我就知道不用看下去了,太水了。
    jy28520
        68
    jy28520  
       2020-08-04 11:22:55 +08:00
    @KalaSearch 想问下我们现在的业务需要验证用户提交的 SKU 和优惠券是否匹配 请问 URL 应该怎么设计那?
    我们会有几条 SKU 和几条优惠券的信息
    b0644170fc
        69
    b0644170fc  
       2020-08-04 11:36:51 +08:00
    根本不需要 rest, get / post 走天下
    imhxc
        70
    imhxc  
       2020-08-04 14:24:18 +08:00
    @fy 嗯嗯,ACL 是可以解决刚才提的问题。
    但是总感觉 REST API 规范有局限性,自己曾经做过 ERP,会经常出现较为复杂的接口,感觉很难严格遵守 REST API 风格。

    比如有一些无法区分上下级关系、获取同一个数据,有的需要用 iD 查,有的需要用 MD5 查,总之,实际业务中各种千奇百怪的需求。

    我以前自己写接口用 REST API 写着写着就要精神分裂了。。。😓

    也可能是我没理解 REST API 的精髓😅
    no1xsyzy
        71
    no1xsyzy  
       2020-08-05 11:00:25 +08:00   ❤️ 2
    @imhxc #70 除非你能直接塞图灵完备的代码进数据库,不然什么都有局限性
    就是 SQL 有时不得不分成两个查询( SELECT ),虽然完全就是数据库里的内容,之后可优化为一次数据库交互包含两个查询(避免传输),但一个(对人脑来说)本来看上去非常简单的东西,不通过逻辑检验竟然无法简化。

    实际上 RESTful 不是有局限性,而是它就是局限性本身:通过强加某种限制,将(一次) API 请求类比为对(一项)资源的操作,形成某种直觉映射,来理清思路。要 “改” 到 RESTful,并不是改动 API 就行的,而是整个建模得修改。
    有人[谁?](忘了谁)认为其实是启发自 Unix 的文件操作。(所以 WebDAV 是 RESTful 最恰当的应用场景)
    imhxc
        72
    imhxc  
       2020-08-05 11:47:20 +08:00
    @no1xsyzy 感谢,涨知识了。
    lolizeppelin
        73
    lolizeppelin  
       2020-08-05 13:13:45 +08:00
    这个论坛早就有人说过了

    RESTful 是对 sql 的劣质模仿,没法表达的情况多去了
    no1xsyzy
        74
    no1xsyzy  
       2020-08-05 14:54:39 +08:00
    @lolizeppelin #73 谁?在哪儿说的?
    RESTful sql 劣质模仿 site:v2ex.com 只搜出来你说的话……

    从来从来,RESTful 就是个和 SQL 完全相悖的路线
    SQL 一直在做得越来越图灵完备,添加各种诡异的、我承认确实像是有那么回事儿的、但其实没有也没关系的功能进去。
    RESTful 一直都是那么平铺直叙。谓宾仍然是谓宾,最多用点 HTTP 语义。
    “C 是个对 Lisp 的劣质模仿”
    lolizeppelin
        75
    lolizeppelin  
       2020-08-05 15:12:12 +08:00
    @no1xsyzy
    est 说的 嘿嘿
    no1xsyzy
        76
    no1xsyzy  
       2020-08-05 15:16:09 +08:00
    @lolizeppelin #75 @est 在哪说的?
    楞是没搜到……
    lolizeppelin
        77
    lolizeppelin  
       2020-08-05 15:17:08 +08:00
    @no1xsyzy
    当然个别字有出入呗,你找他 233333
    est
        78
    est  
       2020-08-05 16:12:31 +08:00   ❤️ 1
    @lolizeppelin
    @no1xsyzy

    我也不记得在哪里说的了,但是中心思想是,RESTful 本来是对文件读写的一个 增删改查 的封装,最适合拿来做 WebDAV 之类的工具。然而其他的业务的「动作」很可能无法用这 4 个指令覆盖。就多出来了很多奇葩的指令比如 OPTIONS TRACE PATCH 。。。与其这样,还不如直接根据具体业务在 url 里指定动作名称。比如

    POST /api/user/login
    POST /api/order/cancel



    然后我是明确反对把 URL 里直接嵌入 resource id 作为路径一部分的。比如 GET /myitem/12345/ 这种,RESTful 一时爽,nginx 日志分析火葬场。
    no1xsyzy
        79
    no1xsyzy  
       2020-08-05 18:38:56 +08:00
    @est #78 本来指令就随便添加,过分绑定到固定四个指令有点先辈的罪或者思维定势。
    我觉得 POST .../login 没什么问题,我的某个工具里面 Login 是类名,将 Login 视为名词形式。
    同时我觉得 POST .../order/cancellation 也没什么问题,是订单状态改变。DELETE order 和它是根本上不同的两种行为。如同 rm 一样,DELETE 谓词的使用应当慎之又慎。
    一般这类框架会有自己的日志的,不用 nginx 分析日志。而且如果不分 /api/* 的 URL 出来的话,也就是 /static/* 让 nginx 处理,其他都归框架管了。而且看到某 PHP 应用的官方部署教程是关掉 /static/* 的日志的…… 基本上 nginx 日志存在有意义的信息就已经是系统层面的大问题了(比如 uwsgi 挂了)
    putaozhenhaochi
        80
    putaozhenhaochi  
       2020-08-11 20:28:03 +08:00
    老哥这么拼
    iplayio2019
        81
    iplayio2019  
       2020-08-12 00:54:23 +08:00
    @est /user/login 这种可以抽象成 session 资源,restful 很强调“资源”概念,POST /api/sessions,登录就是创建 session 。
    注销登录 DELETE /api/sessions/me

    取消订单本身就是状态更新,PATCH /api/orders/{orderID}
    <status>:<取消状态的值>
    est
        82
    est  
       2020-08-12 10:08:43 +08:00
    @iplayio2019

    那么问题来了

    1. 一次登入多个站点的 SSO 怎么设计 URL
    2. 订单拆分、合并操作如何表达?
    3. 上面的同学提到的,批量操作如何写{orderID} ?
    lovedebug
        83
    lovedebug  
       2020-08-12 10:15:28 +08:00
    @est
    RESTful 规范描述的是资源,对于非资源的情形一般需要自定义 action,这一方面大厂已经做了详细的设计,落实到具体设计就根据各自情况做了
    比如你的描述提到的
    1, 一般写成 POST /users/${userId}/login?type=sso 或者 login?user=xxx & type=xxx
    2,一般会写成 POST /orders/${orderId}/$spilit 或者 POST /orders/${orderId}/$merge {ids:[]}
    3 一般写成 POST /items/$batchUpdate {ids:[]}
    est
        84
    est  
       2020-08-12 10:34:00 +08:00
    @lovedebug 其实你 2 和 3 已经是另外一种风格的 URL 设计了。。。还不如干脆一条路走到黑全按照这种风格来设计

    1. POST /user/login
    2. POST /order/split POST /order/merge
    3. POST /item/batchUpdate

    多干净统一。


    RESTful 就是被 UNIX 那种「所有东西都是文件」思想毒害的。遇到完全不像文件或者资源的东西,瞎搞。
    lovedebug
        85
    lovedebug  
       2020-08-12 10:46:29 +08:00   ❤️ 1
    @est 对于自定义 action,RESTful 本来就没有统一,自定义 API 风格各个团队根据自己需要定义就可以
    两种方案
    1. 将资源 uuid 描述在 URL 中
    2. 将资源 uuid 描述在 body 中
    我们两人上面的就是这两种方案的体验,没有好和坏,只看对于 API 使用者的可读性。
    微软和谷歌,github 对于自定义 action 也是分别有自己的实现
    no1xsyzy
        86
    no1xsyzy  
       2020-08-12 13:34:32 +08:00   ❤️ 1
    @est #84 问题不在于 “一切皆文件”,而在于纯远端操作。
    文件是对于 “可读可写” 的抽象。举上述你提到的例子:
    1. 登录是一个状态,SSO 是一个多服务端共享的状态,可读可写,而且读写经过客户端传递,与文件这一抽象完美契合不成问题。
    sub_site 302 到 //sso_host/user/login?to=sub_site/user/login
    然后由 sso_host 确定后 302 传递 token //sub_site/user/login?with_token=~~token~~
    类比: $ cat sso/token | authorize sub_site

    2. 拆分合并的核心在于它是个纯远端操作。一般来说在 Unix 下拆分文件,不出意外是 head|tail 或者 awk/sed 之类,或者对特定的文件类型也是专门的提取器而不是单独的拆分装置。然而无法保证拆分的准确性。那么显然,正确的操作应当是写一个专门的脚本完成这件事 —— 类比过来,就是新谓词。
    SPLITORDER /orders/<orderId>,请求体发送拆分准则之类的,返回 200 内容是拆分结果。
    类比: $ split_order "site/orders/${orderId}" [--options ...]
    site/orders/a site/orders/b site/orders/c

    3. 批量操作可以借用 glob,也可以是单独谓词。后者不必说,前者比如:
    PATCH /orders/{a,b,c}
    Content-Type: application/json

    {"coupon": "foobar"}
    est
        87
    est  
       2020-08-12 14:58:13 +08:00
    > SPLITORDER /orders/<orderId>,请求体发送拆分准则之类的,返回 200 内容是拆分结果。

    对对对。。就是喜欢 RESTful 原教旨主义者这种一本正经发明 1000 个新词的想法。。。。

    反正我对 http 的 verb 就认同 2 个,读是 GET, 写就是 POST 。你们觉得 1000 个新词最血统纯正我也没办法。。。。
    est
        88
    est  
       2020-08-12 14:59:29 +08:00
    @lovedebug 我也差不多是这个观点。RESTful 其实没必要完全照搬。取其精华,去其糟粕。团队内部统一认识就行。
    ChristopherWu
        89
    ChristopherWu  
       2020-08-12 17:25:26 +08:00
    @est
    @no1xsyzy
    @lovedebug

    RESTFul 是不是还有一个问题就是,强绑定于 HTTP ?
    假如我的业务除了 HTTP 接口给外部团队使用外,还要提供二进制协议的接口给内部团队使用,那么 Restful 就不通用了。
    相对来说,使用 RPC 风格的协议,可以统一 API,不管什么,code,message,data 三个字段封装起来就是业务层,其他 code 是协议层的事情。
    brickxu
        90
    brickxu  
       2020-08-12 18:44:05 +08:00
    你这涉猎够广的,另外一个贴子里还在分析 NoSQL,这边直接换到 API 设计了,然后全是 kala 搜索的域名。
    no1xsyzy
        91
    no1xsyzy  
       2020-08-12 19:27:24 +08:00   ❤️ 2
    @est #87 奇妙,我根本不是原教旨主义者
    我跟你讲,原教旨主义者的看法是,拆分订单就是删除旧订单,然后建两个新的。
    至于批处理,原教旨主义者认为就应该发 100 个请求,服务器被撑爆就应该扩容、增技术 balabala 。

    建新谓词是传播主义者的一支,把 RESTful 当 RPC 用。
    est
        92
    est  
       2020-08-13 10:29:43 +08:00
    > 我跟你讲,原教旨主义者的看法是,拆分订单就是删除旧订单,然后建两个新的。
    > 至于批处理,原教旨主义者认为就应该发 100 个请求,服务器被撑爆就应该扩容、增技术 balabala 。
    > 建新谓词是传播主义者的一支,把 RESTful 当 RPC 用。


    我石化了。。。。
    AlbertChen
        93
    AlbertChen  
       2020-09-18 09:38:45 +08:00
    @gnozix 返回 JSON, 里边包含下载链接啊
    goodboy95
        94
    goodboy95  
       2020-09-18 10:05:46 +08:00
    反正我从来不设计 RESTapi,我只设计 api,只是长的有那么点像 REST
    fhsan
        95
    fhsan  
       2020-09-18 10:40:05 +08:00
    怎么来说呢,内部自己的小项目都是 rest,对外的一律 post,因为你不知道对方有啥骚操作
    kokodayo
        96
    kokodayo  
       2020-09-18 11:55:52 +08:00
    @lolizeppelin REST 是,RESTful 就还好啦,毕竟部分思想还是好用的,而且 ful 到什么程度也是开发者自己说了算→_→
    icew4y
        97
    icew4y  
       2020-09-18 16:44:53 +08:00
    restful 就是一残废
    abersheeran
        98
    abersheeran  
       2021-03-09 12:22:47 +08:00
    @fhsan 哈哈哈哈哈哈哈哈哈,对。我写的一个 RPC 框架,全都是 POST,具体内容全部走 Body 。大家都很满意(指服务端开发和客户端开发)。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1035 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 19:57 · PVG 03:57 · LAX 11:57 · JFK 14:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.