V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
CoderLife
V2EX  ›  程序员

请教两个 API 设计的问题

  •  
  •   CoderLife · 2021-03-06 11:42:43 +08:00 · 4143 次点击
    这是一个创建于 1390 天前的主题,其中的信息可能已经有所发展或是发生改变。
    1. 前台和后台需要请求同一个 Api, 如设备列表: /device/list, 但是前后台请求的权限的不同, Api 里有做判断, 返回的内容个数有所不同(如后台返回所有, 前端返回登录用户自己的设备), 疑问: 前后台同使用一个api /device/list还是前台端分开?做成两个 Api?

    2. 同一个 Api, 设备列表: /device/list, 返回的是device表相关的内容, device的字段有很多, 对于不同的请求来源, 需要的字段不同, 如: 有些地方, 只需要nameid, 有些地方却需要返回所有字段 , 甚至需要返回一个deviceowner(设备所有者表)的关联. 这个也是用同一个 Api? 靠用传入参数来控制返回的字段吗? 还是做成多个 Api?

    多谢各位大佬

    19 条回复    2021-03-08 10:54:12 +08:00
    gibber
        1
    gibber  
       2021-03-06 11:58:01 +08:00
    我会倾向于 1 和 2 都做成一个,用参数来控制
    dzdh
        2
    dzdh  
       2021-03-06 12:01:35 +08:00
    根据请求参数生成环境变量,db 和 response 的 filter 根据环境变量调整 where 条件和输出过滤
    xuanbg
        3
    xuanbg  
       2021-03-06 12:03:08 +08:00
    两个接口,同一个实现,不过接口在调用实现的时候参数不同
    renmu123
        4
    renmu123  
       2021-03-06 12:21:46 +08:00 via Android
    1. 前后台的 token 应该是不一致的,靠这个来区分权限
    2.直接全部返回,让前端自己玩去
    zhuzhibin
        5
    zhuzhibin  
       2021-03-06 12:22:22 +08:00 via iPhone
    抽象实现一个 interface 例如 定义 getDeviceList 方法 统一一个接口给外部调用 暴露一个参数 例如平台 前端?后端?或者第三方?对于不同的平台单独实现各自逻辑 对于调用方是同个接口 这样避免以后会有多种情况 不同处理 只需要改动各自平台下面的代码
    MarioLuo
        6
    MarioLuo  
       2021-03-06 13:44:29 +08:00 via Android
    两个接口,接口层应该专用,对数据安全、权限、后续修改都方便,通常情况下 C 端和管理端是两个应用 xx-admin-api, xx-web-api
    gollwang
        7
    gollwang  
       2021-03-06 13:47:51 +08:00
    1.两个接口,前后台分开
    2.个人建议专门的 api 干专门的事,方便排查问题,也方便查询,这其实也算是一种解耦
    Sunyanzi
        8
    Sunyanzi  
       2021-03-06 14:31:23 +08:00
    第一个问题取决于前后台 token 是否统一 ... 即所谓「登录用户自己的」里面的登录用户是否包含权限 ...

    如统一则用同一个接口且需要用不同的入参标识 ... 不统一必须分开 ... 否则鉴权没法做 ...

    第二个问题 ... 毫无疑问的是同一个 API 使用入参控制返回的字段量 ... 我甚至不想过多解释 ...

    API 的设计原则里面有两条可能对你这个情况有用 ... 我顺便一提 ...

    其一是「相似数据同接口返回」 ... 以你的例子而言 ... 既然都是 all device list 理应在同一个接口 ...

    其二是「在设计时不留彩蛋」 ... 即不要设计某个 API 会在某种特殊的情况下返回和平时完全不同的数据 ...

    说到底 ... 这事情就类似于方法重载 ... 使用不同入参获得不同返回的同时避免方法本身产生歧义 ...

    以及设计 API 的时候需要放眼整个系统 ... 毕竟 /device/list 只是一个巨大系统中的小小一块 ...

    不要受限于局部 ... 毕竟一叶障目不见泰山 ... 把能想到的所有系统功能理出来 ... 设计起来也会容易一些 ...
    crclz
        9
    crclz  
       2021-03-06 14:52:01 +08:00
    第一个问题:分开做 2 个接口、合并为一个接口 这两种做法,从写代码层面上来说,普通程序员是可以轻松实现的,不存在困难。

    但是,最重要的是,要考虑到前后台 Api 在之后的开发阶段会不会朝着不同的方向演化。

    现在阶段,前后台 Api 的差距,看似只是返回信息的数量的差距。
    但是,在之后的开发阶段,两个 Api 可能朝着不同的方向演化,并且二者的差距越来越大。
    面向后台的 Api 可能会附带上其他的监控方面的数据,面向前台的 Api 可能会附带其他的向用户展示的数据。

    如果之后这样演化,那么再继续共用一个 Api 地址,就显得很混乱。面向后台的 Api 的修改,很可能牵涉到前台的变动。

    所以,第一个问题的核心,就在于两种 Api 在之后会不会朝着不同的方向演化。

    ---

    第二个问题:这是 overfetch 的问题。一个可选的解决方案是 graphql 。此外,如果要在 restful 基础上来改进的话,就应当偏向于返回更多的数据,来降低开发中需要考虑的情况数量。

    返回更多的数据会造成 overfetch,会造成带宽资源的消耗,同时也会降低开发的复杂度。并且,如果带宽资源不紧张,就可以不管。
    如果带宽资源紧张,根据二八定律,只有那 20%的接口最消耗带宽,所以就只需要用某种带宽资源的 profiler 找出最消耗带宽资源的那四五个的接口进行修改,让它们不要返回过多信息,或者拆分为更细粒度的接口。
    neoblackcap
        10
    neoblackcap  
       2021-03-06 15:05:24 +08:00
    一个接口最好是只做一件事情。既然是不一样的东西,那么就应该分成两个接口。否则这个接口跟万能接口有什么区别?
    至于第二个问题,我看过很多设计方式,有 graphql,有额外加一个 include 的查询参数的,都是解决方法。一般不会因为这个而多开几个 API ( endpoint )
    lecher
        11
    lecher  
       2021-03-06 16:15:01 +08:00
    这两个问题的共同诉求有两个
    1. 数据有权限,终端的请求天然有身份,且不同身份对数据的权限不一样
    2. 终端查询需要更强的自主性了,局限于服务端出固定结构的数据接口不能很好的解决问题

    可以从这几个方向评估新的方案
    1. 数据是否可以使用一套公共的权限方案,管理员可以看所有,个人只能看自己这类的
    2. 是否要给所有的终端一套签发 token 的方案标识身份
    3. 能否提供一套 DSL 查询方言给终端,让终端可以自主解决查询数据的几个问题,裁剪字段,联表等

    仅靠 restful 之类的 API 设计方案解决不了终端日益膨胀的数据查询需求
    imycc
        12
    imycc  
       2021-03-06 16:28:16 +08:00
    1. 提供两个接口,内部可以同一个查询的实现,再根据不同的规则,对不同接口提供数据。
    这样的好处是无需在一个接口内部做过多的参数判断和权限判断,容易横向拆分。

    2. 仅仅只是返回内容的字段数量存在差异的话,意味着数据对于该账号都是可见的,直接做到一个 API 就行。
    直接返回也没什么大碍。如果是请求量巨大,或者内容巨大,需要精简的,那么通过查询参数控制就好。
    Achiii
        13
    Achiii  
       2021-03-06 16:52:28 +08:00
    1.一个接口,通过不同的认证 /token 区分,认证关联权限
    2.一个接口,通过参数实现返回不同字段。比如 type1 是 name,id type2 是 name,desc 。如果返回数据不敏感,可以全部返回让前端自己对接
    eason1874
        14
    eason1874  
       2021-03-06 17:13:47 +08:00
    最好分开,用户的放到用户 API 下

    GET /v1/devices

    GET /v1/devices/ids

    GET /v1/devices/relationships

    GET /v1/users/current/devices
    muzuiget
        15
    muzuiget  
       2021-03-06 18:19:55 +08:00
    江湖规矩,不用纠结,后端先按自己的舒服的做法实现一个,然后再在外面包装“薄层”做转换过滤,以取悦前端。

    按你的需求,就是内部一个 API (对数据库之间),搞个“薄层”暴露两个 API,并带不同默认参数。
    mikael
        16
    mikael  
       2021-03-06 23:51:32 +08:00
    一个 api 一个功能,简单明了,方便后面人的接手,不要搞太多花里胡哨的东西,都是码农,何必互相坑人呢?第二个问题你的 api 可以设置成 /device/list ? from={source} 这种来确定来源返回哪些字段
    goxy
        17
    goxy  
       2021-03-08 03:24:46 +08:00
    第一个还是还是看复杂程度和开发时间,比如我们之前开发的系统原本设计只有两个固定的角色,后来角色越来越多,权限这块全部放在同一个权限处理层做掉了,压根就不需要分多个 api 。根据 restful api 和 url 本身的定义,你在请求一个资源,如果是同一个资源,他就是同一个 url,具体怎么判断是不是同一个资源我们之前的依据是数据结构是不是一致

    第二个 80%的业务不用考虑,直接返回所有的字段,如果是因为权限问题,回到问题一。这个也就是 restful api 的缺点之一,也催生了后面的 graphql 的出现。软件设计过程中就是在做各种取舍,在效率和开发时间上,做好平衡
    lldld
        18
    lldld  
       2021-03-08 09:15:07 +08:00
    我倾向于一个表一个 api, 每个 api 都支持限定字段查询, 限定返回字段
    /<API-Name> 返回所有数据的所有字段
    /<API-Name>?<FIELD1>=xxx&<FIELD2>=yyy 返回部分数据的所有字段
    /<API-Name>?<FIELD1>=xxx&<FIELD2>=yyy&fields=<FIELD3>,<FIELD4> 返回部分数据, 且只返回 3,4 两个字段

    这里做 3 个 api
    /device
    /user
    /device_with_user: 这个会内调 /device 和 /user, 然后 join 数据
    unco020511
        19
    unco020511  
       2021-03-08 10:54:12 +08:00
    同一个接口,根据不同客户端标识返回不同的数据(但结构需要保持一致)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6012 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 01:56 · PVG 09:56 · LAX 17:56 · JFK 20:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.