Rails API 设计参数传递使用 id 是最佳方案?

rubyonme · 2015年09月09日 · 最后由 rubyonme 回复于 2015年09月18日 · 4929 次阅读

需求描述

类似电影院的选座需求,在下单的时候传递预定的座位

问题

关于下单的 API 设计,在传递座位参数的时候是传递座位 seat 的 id 更好,还是传递如 A-1 这样的人容易理解的参数更好?

相关背景

目前团队内争议较大,争议的地方存在以下几个方面:

1. API 数据设计不需要考虑人的可读性,所以应该传 id
2 . 数据库查找的时候,使用 id 性能更好
3. 使用座位号如 A-1,程序里还要去分割处理

我的观点

1. 可读性是更重要的
2. 性能不应该过早优化
3. 使用座位号,这样会把座位号当做一个整体处理,更契合业务逻辑

想征求一下大家的意见,哪种设计会更好?

我假设你说的 ID 是数据库自增 ID, 那么可能会有这样几个问题:

  • 更容易被爬数据
  • 有泄漏商业机密的风险

你说的这个场景电影院的选座需求, 使用 ID 就好了。十分方便,符合 Rails 的约定,方便 debug 和找日志

安全性就吧楼主的观点给否了。。。 “友商”鼓励你注重可读性

这个不是什么可读性的问题,毫无疑问当然是 ID 了。座位号又不是一个独立的资源,每个电影院都有 A-1。你要传座位号的话就得把电影院 id 一起传,后台再找电影院再找座位号,又慢又麻烦。 前端也会很简单,假设用 jquery, 一个座位一个 data-id, 选中直接发送请求,收工。

@billy ,对于下单来说,已经有具体的上下文确定了电影院以及上映影片了,所以传递 A-1 就可以唯一确定座位了。

@rubyonme 对于生成一个订单来说,座位 id, 场次 id, 用户 id(可能还有其他)是必须的,为了凑齐这几个已经需要好几个 query 了,我觉得不必再增加不需要的东西。

可读当然也是必要的,但你可以把附属的信息比如电影院 id, 名字,电影名字,时间,座位号等等在订单生成时存入订单,这样后面可读可查。

@billy , 座位 id, 场次 id, 用户 id 这些都是有的,现在讨论的是 API 的设计问题。

这个问题怎么会牵扯到可读性呢?LZ 你举个例子看看?

@rubyonme 这不就是说的 API 吗。POST, 要求:user token, scene_id, seat_id, 成功就主要返回订单号及付款 token,或者其他附属信息比如电影名字,影院座位号等等方便客户端显示,基本的不就可以了。

接口参数又不需要人力维护,对程序来说当然是性能更重要。如果座位号进行业务处理更方便的话,可以把接口包装起来再通过座位号进行业务操作呀,楼主觉得的?

从我做过的项目来看 ID 好,ID 好,ID 好。不过每个项目都不尽相同

ID 全局唯一性,在下单这个 界限 里,并不需要全局唯一性,只要 A-1 就可以唯一确定。传递的参数也属于 数据 ,数据可读性更高对于程序的维护性会更好吧,我的理解。

😢 形势一边倒啊,谁来救救我。。

#12 楼 @rubyonme 形势一边倒,你就该从自省是不是自己错了。 如果传 A-1 这样的还得验证这个座位在这个影院这个场次是否越界。。比方传 A-9999

@sercoID 也要验证是否属于本场电影..

#14 楼 @rubyonme 传 id 验证简单还是座位验证简单? 座位验证还要读出来一个电影厅的座位表,parse 出来看是否有你传的座位号

#14 楼 @rubyonme 另外我认为 API 的可读性是指约定参数名称是否可读,并非参数值是否可读,否则把 ID base64 一遍的都该拖出去斩了

这是我找到的两个 API 设计

{
    'objects': ['A-3', 'A-5', 'A-7'],
    'event': '767f0050-5af5-4cba-b262-7bf905dd5acf',
    'secretKey': 'c7366b35-b08d-4fc3-b8ab-f3e706dd3a2a'
}
<CustomSupplierParameter>
      <Name>SeatOptions</Name>
      <Value>5477-1A;5470-1E;4550-1F</Value>
</CustomSupplierParameter>

#17 楼 @rubyonme 除了这两个,别的都是传 ID 吧?lol Rails convention 很强很强的,不用 ID 的话不单单损失性能,还得损失一部分功能。

可读性问题我跟楼上一致,key 可读就好了,value 不需要什么可读性

#18 楼 @blacktulip 赞同

像我们平常最常用的 Post.find(params[:id]) => Post.find(1) 上下文已经让这个很好读了 并不需要 Post.find("The first post of hello world").

我只是有很多疑惑的地方,按照这种做法,所有的情况下都应该传递 ID ,那传递 ID 就是 银弹 ,我们都知道是没有银弹的,那么在什么时候不应该传递 ID 呢?

#20 楼 @rubyonme 不想让人推断出数据的时候吧

用 rails 的只是习惯了都是用 id 罢了,楼主的考虑也不无道理。可读性任何时候都是有价值的,无论是数据还是程序。

使用 ID 最好。

不过在做这个 API 之前,验证请求的访问者。

不建议使用A-1这种方式,这种情况加大了程序的复杂度。违背单一职责原则。如果 PC,无线,其他平台都需要使用你这个接口,那么是不是,这几个平台都需要重写一下解析A-1这段代码呢?

本来很简单的东西,考虑的情况太多,反而影响自己的判断。不论任何设计,都应该以简单松耦合单一可扩展为基础准则。

#20 楼 @rubyonme 不是所有的。 首先 Rails 有自己的约定,约定优于配置,说明绝大多数情况下用 ID 是更好的选择。 至于非 ID 的设计,我能想到这么 2 个。

  • 不想让人穷举。防止别人开个循环然后遍历你的 ID 扒数据。
  • 非 API 情况下,在 URL 层面上提供可读性更好的地址。

ID 与其说是便利,不如说是一种 强约束。使用 ID 要求调用者使用 API 提供方定义的全局唯一 ID,那么其本质也是一种 中心化 。当需求不是一种中心化管理的时候,也就是并不是所有的 座位 资源都由 API 提供方管理的时候,使用 A-1 明显是更好的方案。 当需求是 座位资源都由 API 提供方管理 时,我也没感觉使用 A-1 会明显比 使用 ID 差。就把 A-1 当做 ID 一样使用就可以了。

可读性是针对人而言的,api 需不需要人去读?api 是给机器去消费的吧? 问题域中的座位编号用模型域中的 id 去表示,我觉得很直观啊。

看来楼主是铁了心用 A-1 了。既然说不通,那楼主就用 A-1 呗,反正也是能用的,死不了人

如果你的数据库主键用 A-1,也没什么话说。如果不是的话,最好做好 A-1 和电影票 id 的唯一约束。

不然后台人员增删座位会让你疯掉。

介于上面的原因,还是 id 吧。

所谓的“调用者”不是你们自己做的客户端或者网站?你不能控制用最好方案?就算是第三方的,不用先取到座位号就可以下单?你说 A-1 好,但你也要客户端能输入 A-1 而不是甲 -1 之类乱七八糟的格式,难道就不需要中央控制?

再说速度,demo 或小批量数据当然看不出来 A-1 会比 ID 差,数据量大了数据库的索引就不是摆设了。

可读性必胜,损失的那点性能不值一提,另外使用索引没有性能损失。

还没有涉及到性能问题的时候,却拿性能来反推设计,这思路明显有问题。 对于 API 调用来说,只管座位号就行, ID 对于调用方根本没有一点用。这里只需要一个 就能解决问题,却要引入使用 ID 的对象。 引入对象 就意味着引入了 对象之间的导航, 把原本简单的设计复杂化。 我只是不相信有什么所谓 使用 ID 是最佳方案、使用 A-1 就比 ID 差的说法。

你要用就用,谁也不能拦着你。既然有定论了就不用问问题了,直接发使用经验就可以了。有你这么多时间纠结,别人一两个迭代都做出来了。

同意楼上的,最好的方案通常不是讨论出来的,一般自己认定的东西就很难改变了。自己用用就知道了,现在的软件迭代速度都很快。用完了,再回来看看。没什么问题就继续用,不好就重构。

最近在公司也遇到类似的问题。公司的设计师要让我把所有的 URL 里都不能有下划线 (underscore),得用横线 (dash)。我就说为什么连 Google 爬不到的地方也要这么做。设计师说 URL 客户可以看到,我们得统一。

扯远了。楼主为了可读性其实要这么做当然没有问题。但是如果哪天电影院的人觉得 A-1 太不方便了 (中间那个横杠怎么读啊??),他们要换成 A1,又或许要变成甲 1,哪你不是很要做多很多工作吗?

关键在于分析业务里哪些是可能发生变化的 而不必纠结于表面的调用参数

某眼的下单

POST 参数

seats:3:08 // 3排8号
seatTypes:N
seatsNo:
sectionId:0000000000000001
sectionName:普通区
showDate:2015-09-25
showId:54567
poiId:656918
originalPrice:38

我觉得 ID 有点被滥用了,并不是有 ID 就一定要传 ID,很多时候传一个 会更清晰,扩展性也更好。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号