V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
ifane
V2EX  ›  Python

RESTful 风格下,一个 Action 需要对多个资源操作要如何理解?

  •  3
     
  •   ifane · 2018-08-07 11:25:40 +08:00 · 10550 次点击
    这是一个创建于 2336 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如前端有一个按钮,这个按钮表示「去结算」,这个「去结算」代表了后端需要执行一系列的操作:更新订单资源,创建该订单对应的物流资源,更新用户余额。

    这个系列的操作如果交由前端来逐个调用:先调用 A 接口表示更新订单,A 成功返回 200 再调用 B,B 成功返回 200 再调用 C.
    感觉这样实现不太合适。
    53 条回复    2018-08-08 11:20:59 +08:00
    582033
        1
    582033  
       2018-08-07 11:43:34 +08:00   ❤️ 1
    你这属于事务处理了吧, RESTful 应该避免同时对多个资源进行访问的吧. 有关事务还是需要避免使用 RESTful 的.

    提供个参考链接:
    https://stackoverflow.com/questions/2346964/if-transactions-over-rest-are-unachievable-how-can-rest-ever-be-really-useful

    如果有误,欢迎楼下指正
    lookas2001
        2
    lookas2001  
       2018-08-07 11:50:06 +08:00 via Android
    别太死板,变通一下。
    如果说就是更新一个或几个东西的信息,那标准的 restful api 就可以解决,各大对象存储就是这种情况。
    如果说需要多个操作,不想多发请求或者说是很复杂的逻辑或者说是干脆就没有什么资源就是一堆计算。
    那创建一个 POST /do-someting 的 api 又如何呢?
    lihongjie0209
        3
    lihongjie0209  
       2018-08-07 11:55:15 +08:00
    公开数据接口我见过 rest, 但是内部业务接口就算了吧, 用几个动词想描述所有的业务需求那就是在开玩笑
    jasonyang9
        4
    jasonyang9  
       2018-08-07 11:56:47 +08:00
    MVC 的话应该放到 Controller 里面去做吧?
    feiyuanqiu
        5
    feiyuanqiu  
       2018-08-07 12:01:42 +08:00 via Android   ❤️ 1
    leoli
        6
    leoli  
       2018-08-07 12:04:12 +08:00
    可以重新定义资源,资源不一定是数据库里一张表的数据吧。
    est
        7
    est  
       2018-08-07 12:06:12 +08:00
    发明 RESTful 的人就是个做外包忽悠人的。世界上对资源操作的行为这么丰富,非得必须封装成对资源的增删改查,还仅限这四种?有病。
    FrankFang128
        8
    FrankFang128  
       2018-08-07 12:06:40 +08:00
    这就是 order#update 吧
    lolizeppelin
        9
    lolizeppelin  
       2018-08-07 12:12:05 +08:00 via Android
    直接返回异步任务 ID 和预计完成时间

    异步任务结果有统一数据结构

    到达时间点就通过异步任务 id 去拿结果
    lolizeppelin
        10
    lolizeppelin  
       2018-08-07 12:13:43 +08:00 via Android
    按照一般设计 后端这个系列操作应该 rpc 出去
    让一个专门负责这类操作的服务去做
    TommyLemon
        11
    TommyLemon  
       2018-08-07 12:20:20 +08:00
    RESTful 只适合对单表的单个操作,在 10 年前还是个好东西,一套标准减轻了前后端的沟通成本。
    随着互联网的飞速发展,需求越来越复杂,对单表的单个操作这种需求就越来越少,
    RESTful 已经不适用了,而且前后端关于接口的沟通问题也越来越严重。
    github.com/TommyLemon/APIJSON/wiki


    APIJSON 自动将前端传的 JSON 参数转为 SQL 语句执行并返回结果,
    期间自动校验权限、结构、内容,自动防 SQL 注入。

    通过自动化 API,前端可以定制任何数据、任何结构!
    大部分 HTTP 请求后端再也不用写接口了,更不用写文档了!
    前端再也不用和后端沟通接口或文档问题了!再也不会被文档各种错误坑了!
    后端再也不用为了兼容旧接口写新版接口和文档了!再也不会被前端随时随地没完没了地烦了!

    在线解析
    自动生成文档,清晰可读永远最新
    自动生成请求代码,支持 Android 和 iOS
    自动生成 JavaBean 文件,一键下载
    自动管理与测试接口用例,一键共享
    自动校验与格式化 JSON,支持高亮和收展

    对于前端
    不用再向后端催接口、求文档
    数据和结构完全定制,要啥有啥
    看请求知结果,所求即所得
    可一次获取任何数据、任何结构
    能去除重复数据,节省流量提高速度

    对于后端
    提供通用接口,大部分 API 不用再写
    自动生成文档,不用再编写和维护
    自动校验权限、自动管理版本、自动防 SQL 注入
    开放 API 无需划分版本,始终保持兼容
    支持增删改查、模糊搜索、正则匹配、远程函数等

    后端接口和文档自动化,前端(客户端) 定制返回 JSON 的数据和结构!
    创作不易,GitHub 右上角点 Star 支持下吧,谢谢^_^
    github.com/TommyLemon/APIJSON
    learnshare
        12
    learnshare  
       2018-08-07 12:25:23 +08:00
    RESTful 用来描述接口,包括 URL、method 和 data 等信息,与后端和数据库没有关系
    你讲的这一系列操作应该由后端处理,对前端来说只是一个动作
    micean
        13
    micean  
       2018-08-07 12:29:43 +08:00   ❤️ 1
    @TommyLemon 哪都能看到你……
    slince
        14
    slince  
       2018-08-07 12:39:20 +08:00   ❤️ 1
    和数据库三范式一样,适当反 restful 时可以接受的,一个正常的系统都是兼顾二者的

    ## 反 restful

    post: `/orders/checkout`

    ## restful 风格

    上面有人提到资源不一定是数据表;将“结算”抽象成资源,

    post: `/checkouts`
    slince
        15
    slince  
       2018-08-07 12:40:40 +08:00
    @est 你们这是狭隘的理解 restful
    est
        16
    est  
       2018-08-07 13:02:42 +08:00
    @slince 我觉得 GET 读 POST 改就够了。何必分那么多。

    GET /order/status
    GET /order/list

    POST /order/submit
    POST /order/cancel
    POST /order/close


    RESTful 还区分资源的单数复数,真是没事儿找事儿。
    visonme
        17
    visonme  
       2018-08-07 13:13:02 +08:00
    一个操作涉及多个资源,相应这些资源不可能是独立而没有关联的,相反可能还存在某种包含关系,比如订单根订单项还有价格表的关系。

    如果这样,不妨找到聚合根,一个入口对聚合根操作,实现多个资源联动
    jswh
        18
    jswh  
       2018-08-07 13:18:39 +08:00
    restful 的资源是抽象资源啊,又不是对应数据表的资源。看你怎么抽象了,自圆其说。
    bk201
        19
    bk201  
       2018-08-07 13:20:21 +08:00
    前端爲什麽要涉及多個接口,本身設計就有問題,一個接口就是增加結算接口
    passerbytiny
        20
    passerbytiny  
       2018-08-07 13:26:57 +08:00
    用户需求、UI 对象、Restful 资源(可以理解为远程接口资源)、业务对象、数据库表,这几个中,任意两个之间都是不一样的,任何试图将它们进行一一映射的措施都必定会失败,任何试图将它们进行一一映射的想法必然是 S B 的。

    按钮「去结算」是 UI 对象“某个按钮”。
    passerbytiny
        21
    passerbytiny  
       2018-08-07 13:46:21 +08:00   ❤️ 2
    该按钮怎么处理,完全是 UI 自己管的事,Restfu 接口设计时完全不用考虑该按钮要干啥。它需要考虑的是:购物车资源,应该暴漏一个结算行为供远程调用,所以 Restful 接口提供的资源是“购物车 /{id}/结算”。(“资源 /动词”表示资源的某个行为,是合法的 restful 风格)(相应的,UI 那里也只需要调用一下这个接口就可以,它完全不用考虑后续的业务是怎么处理的)

    至于 restful 接口之后的过程,就要涉及到领域模型相关的知识了,这个一时半会说不清楚。大致提一下过程( restful 接口只需要调用购物车的结算方法,不用关心后续过程):
    购物车:结算
    ——》结算事件:被发布
    ——》新建订单监听:处理结算事件
    ——》订单:被创建
    ——》订单创建事件:被发布
    ——》
    [并行] 用户相关监听:处理新订单事件——》用户 /用户余额:减余额
    [并行] 物流相关监听:处理新订单事件——》物流:新增
    [并行] 更多相关监听

    有一个非常重要的点是:要使用 restful 接口,必须要一起使用领域模型设计,而且是启用了领域事件、异步、最终一致性的 DDD。如果还是传统的纯事件驱动模型设计(界面点个按钮,后面巴拉巴拉怎么处理),就不要用 restful 接口,强行使用(比如说动词名词化),很 S B。
    lygmqkl
        22
    lygmqkl  
       2018-08-07 13:52:28 +08:00
    POST /orders //如果是从 shop cart 直接到订单系统
    PUT /orders/o_id //如果是存在订单做后续更新

    然后放到 Model 层 来处理,可以用 Transaction

    具体还是要看架构设计了
    mooo
        23
    mooo  
       2018-08-07 14:21:48 +08:00
    为什么要定义 3 个接口,REST 是抽象的资源又不是具体的表。接口定义一个 PUT 订单就可以了
    zhzer
        24
    zhzer  
       2018-08-07 14:29:28 +08:00
    这种情况要用 restful 除了前端调用起来麻烦,权限管理也是个问题
    最好的方法就是不用 restful
    thinker3
        25
    thinker3  
       2018-08-07 17:16:04 +08:00
    @transaction.atomic
    @action(methods=['post'], detail=False)
    def settle(self, request, *args, **kwargs):
    zvving
        26
    zvving  
       2018-08-07 17:25:08 +08:00   ❤️ 1
    资源 != 表
    资源 == 业务场景实体

    业务场景实体的转换( A->B )和修改( A.a = 2 )都可能导致表修改以及大量业务逻辑。

    问题 1: 去结算
    根据购物车的数据 POST Order 就好,"更新订单资源,创建该订单对应的物流资源,更新用户余额" 这些都是后端逻辑,前端不要管,管了也不安全

    问题 2: 有些场景会有接口 1 调完调接口 2,一般都是接口设计不合理,比如问题 1.

    RESTful 不是银弹,但能满足国内 80% 中小企业的绝大多数场景。而且绝对比开发随意定义的结果好得多。先学会,再去喷……
    zvving
        27
    zvving  
       2018-08-07 17:29:59 +08:00
    @est “发明 RESTful 的人就是个做外包忽悠人的。”

    真是什么话都敢说。不知道你跟 roy 比,谁是做外包的!

    “ Roy Fielding 的毕业论文。这哥们参与设计 HTTP 协议” 出处: https://www.zhihu.com/question/28557115
    unforgiven
        28
    unforgiven  
       2018-08-07 17:34:10 +08:00
    @est 人家好歹也是发过 paper 的,再说了 restful 又不是只对应数据库的一张表,看你怎么抽象
    est
        29
    est  
       2018-08-07 17:52:26 +08:00
    @zvving

    http 也并不是什么好协议。或者说 http 并不是什么场景都适用的。Roy Fielding 也不是什么好人,或者说他的一些观点在当时可能有用。RESTful 发明的时代是 http 1.0 时代。那个时代的东西被淘汰的太多了。他发明的 SOAP 你们今天还有人用嘛?

    Roy Fielding 后来去了 Adobe,按照他老人家的思路去搞了 CodeFusion。这玩意你们有做过嘛?简直各种别扭。


    为毛 RESTful 就那么多人捧臭脚?搞不懂。RESTful 在过去唯一拿的出手的就是 WebDAV。其本身就是各种安全和性能问题一坨浆糊集大成者。其本身就是个 leaky abstraction


    @unforgiven

    RESTful 在上古时期(UUCP 还是个事儿的时期)可能有用,但是现代复杂业务场景下就是胡闹。
    unforgiven
        30
    unforgiven  
       2018-08-07 17:54:56 +08:00
    @est 那这就属于理念不同了,反正对我这样讨厌起名字的人来说觉得 restful 还不错
    est
        31
    est  
       2018-08-07 17:58:53 +08:00
    @unforgiven 其实就算 db 里一张表,我觉得现代的用处也远远超过了增删改查。

    比如 upsert。 比如 on duplicate key update。比如 update a = a +1

    这些都是 fetch-then-update 的操作。有些还得做线程安全。这些我觉得都不能简单的概括。RESTful 根本不能覆盖这些情况。

    就拿最简单的 GET URI 操作来说,页面访问量计数器算不算状态的改变?多次刷新 GET 能否保证幂等?这些问题都是各个人都有一套自己的答案。

    RESTful 是属于蛮荒时期一个方向性的指引,是个不错的大框架。但是现在应用场景那么复杂精细还用这个框架去套就不对了。应该具体业务用不同的方案。
    newtype0092
        32
    newtype0092  
       2018-08-07 18:08:58 +08:00
    @est 感觉你说的前后矛盾啊
    #7 “世界上对资源操作的行为这么丰富”
    #16 “我觉得 GET 读 POST 改就够了”
    所以到底应该怎么样抽象操作啊?
    unforgiven
        33
    unforgiven  
       2018-08-07 18:09:24 +08:00
    @est 说个实在话,我觉得你非要揪住 restful 不能覆盖的情况来看就没啥意思了,就拿后端的管理系统来说一般就是 crud,是不是很适合,没有完美的解决方案,看你自己的选择了
    zvving
        34
    zvving  
       2018-08-07 18:14:19 +08:00
    @est 你说的问题存在,所以说 RESTful 不是银弹。

    RESTful 实体的思考方式有利于梳理大部分的业务,特定场景用别的方案,用呗。怕的是 API 设计一味造轮子,纯把业务搞乱。

    看看主流 Web 框架对它的支持,我也乐于捧 RESTful 的臭脚。
    est
        35
    est  
       2018-08-07 18:25:20 +08:00
    @newtype0092 不矛盾。对资源的操作太丰富,所以规定 2 个大类就够了。4 个 verb 明显不够。比如 OPTION 在实际中就少不了。。。DELETE 也是有 2 意的。其实很多删除并不是删除。而是设置一个已删除的 flag。
    @zvving 其实我比较支持对 资源 的梳理,我主要反对 REST 里把 verb 定义成 4 种 这种做法。太死板了。
    sfree2005
        36
    sfree2005  
       2018-08-07 18:39:10 +08:00
    可以上 GraphQL, 它出现的目的就是为了不用前端 /移动端进行多次请求。 台式机笔记本还好,但如果是移动端,多次请求费电费时间,体验不好,万一中间有网络不稳定的情况,事情就变得很复杂。
    tomxin7
        37
    tomxin7  
       2018-08-07 18:46:01 +08:00
    让后端提供下单接口,你只需要提供需要结算的商品信息就好了,到支付这一步又是其他页面其他接口了。
    lscho
        38
    lscho  
       2018-08-07 19:19:20 +08:00 via Android
    这个问题搞不明白的感觉都是前后端混写的吧。。。restful 资源是抽像资源啊,又不是具体到数据库。

    比如 put /order,表示创建一个订单,与创建订单相关的数据需要更新,后端想咋写咋写。只要暴露出来的接口是这个规则就行。

    再另外,restful 也只是一种设计风格,并不一定要完全死搬硬套。
    duan602728596
        39
    duan602728596  
       2018-08-07 23:52:53 +08:00 via iPhone
    没错,就是不合适,这么干用户不找你麻烦算我输。我之前的公司,后端就是这么个水货,复杂的、涉及到多表的功能就要发送 5、6 次请求,有一步失败了,数据库里就一堆垃圾数据。美其名曰风格,实际上就是给自己的懒惰找个借口罢了
    newtype0092
        40
    newtype0092  
       2018-08-08 00:05:53 +08:00
    @est 我现在只是简单的把只读幂等的一律 GET,有写入的一律 POST,感觉很难把 RESTful 和实际的业务结合起来。。。
    agagega
        41
    agagega  
       2018-08-08 00:48:01 +08:00
    变通一下

    幂等读,可缓存,用 GET
    幂等写,用 PUT/PATCH
    带有删除语义,用 DELETE
    其余复杂的业务,自己设计一个路由然后用 POST
    lrh3321
        42
    lrh3321  
       2018-08-08 07:34:43 +08:00 via Android
    @TommyLemon 勤勉的布道师,我已经见过你不下五次了
    slince
        43
    slince  
       2018-08-08 09:37:37 +08:00
    @est restful 不要狭隘的去理解 restful 抽象的增删改查; restful 概念是出现的比较早,但流行也就是这几年的事; paypal 这么庞大的企业的 api 都已经换成了 restful, 你还觉得它 out 了吗;
    TommyLemon
        44
    TommyLemon  
       2018-08-08 09:55:18 +08:00
    @lrh3321
    哈哈,感觉 V2EX 用户量不多啊。
    我要是有 Facebook 这样的影响力,有一大堆自发地宣传推广 GraphQL 的粉丝,
    我也用不着自己到处去发博客、评论、回复来推广 APIJSON 了,唉。

    APIJSON 全方位对比 GraphQL
    https://juejin.im/post/5ae80edd51882567277433cf
    suley
        45
    suley  
       2018-08-08 10:03:05 +08:00
    @lscho

    我认为 restful 的本意就是同一个资源会共享同一个模型,类似于 Java 对象的定义一样,如果同一种资源不同的接口返回的模型不一样,那么就复杂了。
    qinxi
        46
    qinxi  
       2018-08-08 10:09:52 +08:00
    @TommyLemon 所以这就是你滥用评论的理由?
    qinxi
        47
    qinxi  
       2018-08-08 10:10:17 +08:00
    @micean 这种人 b 了完事
    M4ster
        48
    M4ster  
       2018-08-08 10:15:25 +08:00
    资源 != 表
    est
        49
    est  
       2018-08-08 10:19:21 +08:00
    @newtype0092 我也是这个做法。PUT DELETE 都是笨蛋设计。
    solee
        50
    solee  
       2018-08-08 10:35:05 +08:00
    业务快速发展 Restful 设计理念毕竟也不能满足所有需求。记得以前看过一篇文章,就是对 restful 设计理念的一个变种,但是很实用,我们现在的业务 api 设计也基本按照那个思路来的
    附上链接: https://mp.weixin.qq.com/s/AhiyMnJ70TkOMnmkXG1Lsw
    lscho
        51
    lscho  
       2018-08-08 10:37:56 +08:00
    @suley 前后端的概念一定要搞清楚,抽象资源和实体数据一定要搞清楚。。比如订单,对于前端来说,订单就是抽象资源,对于后端来说,订单不仅仅是订单表,还有用户表,商品表,等一系列与订单相关的,都属于订单。至于前段需要什么数据,就需要后端整合后返回了。

    如果后端说资源=表,那他纯粹是偷懒。
    suley
        52
    suley  
       2018-08-08 10:53:51 +08:00
    @lscho 你说了那么大一堆,有没有解释清楚,同一个资源不同的 uri 请求回来的资源实体不一致的问题?
    lscho
        53
    lscho  
       2018-08-08 11:20:59 +08:00
    @suley 请问哪种情况会出现不同 uri 中的资源会出现同一个资源?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2602 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 03:29 · PVG 11:29 · LAX 19:29 · JFK 22:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.