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

优秀的 REST API 设计指南

  •  
  •   KalaSearch · 11 天前 · 14005 次点击

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

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

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

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

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

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

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

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

    79 条回复    2020-08-05 18:38:56 +08:00
    abbycin
        2
    abbycin   11 天前 via Android   ❤️ 4
    5分钟快3我 八股文写得特别好
    baiyi
        3
    baiyi   11 天前
    5分钟快3我 认为在设计过程中,需要考虑 HTTP 5分钟快3方法 的幂等性。比如 Github 的 Star 操作,为什么是 PUT 而不是 POST,就是从幂等性方面考虑的
    KallyDev
        4
    KallyDev   11 天前 via iPhone   ❤️ 18
    补充一个微软在 GitHub 公开的规范,非常详细

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

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

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

    5分钟快3我 个人认为,只要满足团队要求的 API,就是好的 API 。具体实现各有好处,看团队取舍了
    KalaSearch
        21
    KalaSearch   10 天前
    @ZacksT 感谢回复。是的,满足团队、客户需求就是好 API 。对于5分钟快3你 说的参数定义的例子,GET + URL 参数挺好的,遵从 REST 语义



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

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

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

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

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

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

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

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

    这个5分钟快3我 做了,默认 and 操作,请求类似这样:

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

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

    http://github.com/fy0/slim


    问题主要是几处:

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

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

    3. 连表查询比较复杂。

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

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

    @imhxc #44

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

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

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

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

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

    RESTful 是对 sql 的劣质模仿,没法表达的情况多去了
    no1xsyzy
        74
    no1xsyzy   3 天前
    @lolizeppelin #73 谁?在哪儿说的?
    RESTful sql 劣质模仿 site:v2ex.com 只搜出来5分钟快3你 说的话……

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

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

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



    然后5分钟快3我 是明确反对把 URL 里直接嵌入 resource id 作为路径一部分的。比如 GET /myitem/12345/ 这种,RESTful 一时爽,nginx 日志分析火葬场。
    no1xsyzy
        79
    no1xsyzy   3 天前
    @est #78 本来指令就随便添加,过分绑定到固定四个指令有点先辈的罪或者思维定势。
    5分钟快3我 觉得 POST .../login 没什么问题,5分钟快3我 的某个5分钟快3工具 里面 Login 是类名,将 Login 视为名词形式。
    同时5分钟快3我 觉得 POST .../order/cancellation 也没什么问题,是订单状态改变。DELETE order 和它是根本上不同的两种行为。如同 rm 一样,DELETE 谓词的使用应当慎之又慎。
    一般这类框架会有自己的日志的,不用 nginx 分析日志。而且如果不分 /api/* 的 URL 出来的话,也就是 /static/* 让 nginx 处理,其他都归框架管了。而且看到某 PHP 应用的官方部署教程是关掉 /static/* 的日志的…… 基本上 nginx 日志存在有意义的信息就已经是系统层面的大问题了(比如 uwsgi 挂了)
    5分钟快3关于   ·   FAQ   ·   API   ·   5分钟快35分钟快3我 们 的愿景   ·   广告投放   ·   感谢   ·   实用小5分钟快3工具   ·   2338 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 03:08 · PVG 11:08 · LAX 20:08 · JFK 23:08
    ♥ Do have faith in what you're doing.