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

彦祖们,这种 API 接口设计有哪些利弊?

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

    最近在复刻一些产品做练手,发现了不少新产品的 web api 接口很有意思。两个典型参考对象是 wolai.comtodoist.com

    传统上,我们会根据业务需求给不同的业务设计开发出不同的 api 接口出来给前端调用。

    比如某个系统叫 V2EX,包含了对帖子的增删改查,我们往往会创建

    /article/create
    /article/update
    /article/delete
    /article/get/:id
    /article/list/get

    等接口。

    然后处理分类还有
    /category/create
    /category/update
    等等。

    当然其中还有一些可以合并的,具体不一而足,因人而异。

    但我最近看到了这样一些接口。使用方法类似于

    /article

    然后 payload 为

    {
    	"resource_type": "article",
            "transaction": [{
        	"requestId": "some kind of uuid"
        	"command":"updateArticle",
            "args": {
            	"articleId": some int or uuid,
                "content": "some string",
                "blahblah": "blahblah"
            }
        }]
    }
    

    这个 payload 本身不难看懂,其中 transaction 是个数组,可以一次包含多个指令。

    这个让我想起来以前我们有的时候开的玩笑,说根本不需要写很多接口,只要一个接口,传不同的参就可以干所有的事。现在看来这个玩笑不仅被人真的这么做了,还给了很完善的事务概念。

    但我仍然有些困惑,这样的模式真的很好用吗?

    我能想到一些优势,比如前面可以是一个很薄的 controller, 后面随着 args 的不同调用不同的 service 处理。service 可以很轻松的切换版本,不需要担心和前端的对接。队列在后端的应用也是显而易见的。

    对前端来说,也不再需要看 N 个接口的文档,大多数接口会统一起来有一套标准,只要定义约定好相关的行为和参数就可以。

    但这样的接口调用,是不是本身就太复杂了呢? 我大概想了下,似乎没有看到很明显的收益。我大概看了下相关的前端,有这样一个特性。

    比如说列表页,我新增一个内容,传统模式是先 create,然后再获取 list,进行 data 更新。 现在会改成先操作本地 data,直接在 list 里 append,然后再发一个事务描述,告诉后端去做对应的相关操作。

    我甚至在某个 app 中遇到过事务失败的问题,然后造成了多端登录的情况下有一个端死活同步不了( Todoist,事务 ID 对不上,死活不能同步数据。)

    就想问问各位大佬,这种接口设计除了我自己臆想分析的特征,还有什么别的是我没考虑到的吗?

    littlemcdull
        1
    littlemcdull  
       135 天前
    我能想到的是这种接口挺适用增量更新的,比如,一段时间后服务端新增了若干条数据记录,有删除,有修改,有新增(比如在另外一个终端 iPad 上登录了同个帐号,进行了一些操作,然后又换了个 iPhone 设备同一个帐号,需要从服务端同步数据)
    Morriaty
        2
    Morriaty  
       135 天前
    es 的增删改接口 bulk 也是这个设计方式,和传统的 restful api 有啥优劣,我还真感受不出来,都一样🤣
    javalaw2010
        3
    javalaw2010  
       135 天前
    我个人感觉第二种接口会在应用有离线需求、多端同步的时候使用,比如笔记应用新增一篇文章,你肯定不能因为没有网络而不让用户新增文章,多端同步的时候,A 设备上的操作可能只有部分操作同步到了 B 设备,等到有条件的时候再把剩余的操作同步到 B 设备上,这种情况下第二种的方案会比较方便些。
    sudoy
        4
    sudoy  
       135 天前
    只能说这操作太骚了,随着项目越来越庞大,这个看起来就很费劲了,不管前后端,维护性和可拓展性就慢慢变差了
    zjsxwc
        5
    zjsxwc  
       135 天前
    方便一次接口请求,就能完成原先 restful 方式需要 N 次请求的场景。
    JerryCha
        6
    JerryCha  
       135 天前
    可能它只是个 gayway,真接口隐藏在后面
    ibegyourpardon
        7
    ibegyourpardon  
    OP
       135 天前
    @littlemcdull 其实这个模式我想过,颇有点类似 MySQL 了。
    要实现同步数据,一个是传统的模式,拿最终数据。
    二个是像这种模式一样,拿所有的操作行为日志,再完整走一次,就可以追回最终数据了。

    但我想了下,这种前后端的场景中,走日志的模式代价远比直接获取最终数据高。
    ibegyourpardon
        8
    ibegyourpardon  
    OP
       135 天前
    @javalaw2010 对对对,这个问题我也想过。
    我甚至联想到了游戏服务器上,多玩家联网操作的逻辑同步。

    但引申来了一个新问题。
    我不同端操作先后有别,那我为了保证某种程度的最终一致性,后端除了记录数据,是不是还得记录下来自多个客户端的所有操作,类似 binlog 日志那样。
    感觉又增加了存储队列上的额外操作。
    dream4ever
        9
    dream4ever  
       135 天前   ❤️ 2
    @JerryCha gayway ? gateway ?
    intmax2147483647
        10
    intmax2147483647  
       135 天前   ❤️ 1
    用后者不如用 GraphQL (也有些区别),用前者不如用 http method 区分不同的接口,写个 /create /get 在 URL 里面显得很多余,并不 RESTFUL
    Symo
        11
    Symo  
       135 天前
    我觉得至少 GET POST 语义上一定要区分, 但是后端上只是把本应给 uri 做的正则匹配, 变成了对 json decode 之后的某字段的匹配来区分业务, 性能可能略微受影响?
    securityCoding
        12
    securityCoding  
       135 天前 via Android
    你可以理解为命令模式,现在基本不这样用了
    lanlanye
        13
    lanlanye  
       135 天前
    好处是没有文档你根本不知道这个接口怎么用,坏处也是没有文档你根本不知道这个接口怎么用……
    RESTful 应该也不会写 /create /update 之类的东西
    lux182
        14
    lux182  
       135 天前
    网关路由,限流等不太好做。其他的其实挺好的
    learningman
        15
    learningman  
       135 天前
    GraphQL, 请
    bthulu
        16
    bthulu  
       135 天前   ❤️ 1
    批量操作你的 create/update 接口就不能接收一个数组吗?
    把所有接口统一到一个接口, 你文档怎么写?
    按你这么想, java 要这么多类, 这么多方法干嘛呢, 就一个 main 类, 一个 main 方法, 方法里传不同的参数不就行了吗? jdkAPI 加起来也就几万到几十万吧, 用一个 int 作为第一个入参, 就可以区分几亿个操作了, 够 jdk 用的了. 以后大家的代码就是这样的, 是不是很简单明了, 一看就懂?
    ```
    Main.main(1, xxxx);
    Main.main(16515, xxxx);
    Main.main(568, xxxx);
    Main.main(35656, xxxx);
    Main.main(956, xxxx);
    ...
    ```
    harde
        17
    harde  
       135 天前
    是我精神恍惚了么?早年 Servlet 不就这样么。。。 后来 RESTful 盛行,才慢慢没人这么干了
    Macolor21
        18
    Macolor21  
       135 天前
    @harde 一部分 java 开发除了大学学了 Servlet 之后,就再没接触过,大多都是基于 Spring 框架封装的东西在开发,早都忘了。另一部分可能压根没深入了解 Serlvet
    no1xsyzy
        19
    no1xsyzy  
       135 天前
    在说什么
    这不就是一个变形了的 JSONRPC ?

    状态模式和日志模式的代价难说,如果编辑是稀疏的,那显然日志模式代价小得多。
    奇怪的优势是:日志模式可以减少需要解决的冲突。
    apifox
        20
    apifox  
       135 天前
    用 GraphQL 不香吗?
    gfreezy
        21
    gfreezy  
       135 天前
    这看起来像是 rpc 框架生成的。实际写的可能是类似 gprc 的 proto 文件,只是传输协议用的 json
    Building
        22
    Building  
       135 天前 via iPhone
    一个本地路由。
    一个服务器路由。
    Building
        23
    Building  
       135 天前 via iPhone
    以前用 php 生成模版的时候,路由就已经绑定在按钮上了,现在很多项目都不用后端生成 UI 了,直接 js 获取数据再由前端渲染 UI,这样后端就不需要再绑定路由了,所以一个入口就可以。
    harryhao
        24
    harryhao  
       135 天前
    设置不同接口方便路由,比如不同接口的请求量、认证安全级别可能不同
    whajcf
        25
    whajcf  
       135 天前
    这个好眼熟.. 然后我想到个我目前在用的一个场景: IoT 通信协议的编解码,报文根据不同的功能码携带对应的指令数据...
    waibunleung
        26
    waibunleung  
       135 天前
    我感觉有点像 redis 的 pipeline 模式,管道式执行请求逻辑,一定程度上减少了接口的请求量,还能臆想到的就是能根据 command 来判断哪些 command 是可以异步 /并发执行的,哪些需要同步执行
    jmyz0455
        27
    jmyz0455  
       135 天前
    这种设计我还真没见过。
    wolfie
        28
    wolfie  
       135 天前
    wolai 之前抄袭道歉后 又上线了吗。
    weichengwu
        29
    weichengwu  
       135 天前   ❤️ 1
    @wolfie #28 wolai 从来没道歉过吧?记得之前有个叫什么舟的抄袭道歉下架了
    bz5314520
        30
    bz5314520  
       135 天前
    粗接口可以减少网络往返 ,接口设计粒度的太细就会导致业务逻辑散布到客户端,业务流交给了客户端控制。而且这也可能导致业务域不一致 比如一个上传文章 ,文章标签是必须的 ,你却把 api 拆成 上传文章再附加标签。具体如何抉择看业务,也是自身工程实践考验。软件哲学~~
    111111111111
        31
    111111111111  
       135 天前
    很自然的想到了 GraphQL,JSONRPC 啊什么的。。
    karloku
        32
    karloku  
       134 天前
    api 的 uri 能拆就拆, accesslog 的收集分析现成工具多, 好统计好分析
    用这种单 endpoint 的 rpc 风格就得自己把监控收集分析都定制一套.
    好处大概是比较容易配置新的行为模板, 方便在客户端那边生成按钮.
    charlie21
        33
    charlie21  
       134 天前
    web 开发中,有没有后端完全作为接口提供数据,转发请求等操作由前端 html+js 实现的例子
    https://www.zhihu.com/question/21460500
    2013 年发的帖子,那时候把它称为 重前端应用
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3798 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 08:32 · PVG 16:32 · LAX 00:32 · JFK 03:32
    ♥ Do have faith in what you're doing.