我最近一直在用 groups API 做一些工作,并对分页(特别是在非发现场景下)有一些想法。
背景
为清晰起见,我所说的“发现场景”是指 list_controller.rb 和 tags_controller.rb 中的分页,它们使用类似的 construct_url_with 方法来生成上一页和下一页的 URL。
关于这一点,这些 construct_url_with 方法或许可以合并到一个被包含的模块中,因为它们非常相似。不过,由于这种分页对于主题列表生成至关重要,因此它属于一个相对独立的范畴。
模式
在非发现场景下,分页使用的是以下某种变体:
page = params[:page].to_i
page_size = 38
items = items.offset(page * page_size).limit(page_size)
你可以在各种控制器中看到这种模式的变体(以下列举并不详尽):
- 群组 (groups)
- Web 钩子 (web hooks)
- 邮件 (emails)
- 通知 (notifications)
- 目录项 (directory items)
- 管理员操作日志 (staff action logs)
…
当第三方客户端使用这些端点时,分页存在几个问题。
问题
具体问题:“加载更多”URL 的包含
某些端点即使没有更多页面,也会返回一个“加载更多”URL(包含“下一页”)。
例如,在 meta 上我可以看到 9 个群组。然而,在该页面的 .json 中,会包含一个 load_more_groups 条目,指向一个不存在的第二页(页码实际上从 0 开始,所以页码 “1” 是第二页):
https://meta.discourse.org/g.json
...
"total_rows_groups":9,
"load_more_groups":"/groups?page=1"
这或许可以被称为端点的一个“缺陷”,因为 API 客户端在迭代页面时,通常会尝试使用“加载更多”URL,而不是自己处理页码计数。
一般问题:命名、页面大小处理及返回的分页数据不一致
更广泛地说,在非发现场景下,分页的命名、页面大小以及返回的分页数据存在相当大的差异。例如:
- “页码”有时被称为
:page,有时被称为:offset。 - “项目总数”有时作为
total_rows_*包含在内,但并非总是如此,且有时名称不同。 - 大多数页面大小是在相应操作本地分配给变量的,且各不相同,这意味着你需要深入查找才能找到它们。
建议
当然,我提到的许多问题都有其各自的原因。许多非发现端点主要是(或仅)被 Discourse 应用客户端消费,并针对该客户端进行了定制,这很合理。
尽管如此,这里或许可以推动一项举措,逐步将非发现分页(特别是那些常被外部客户端消费的端点,如群组)向更标准化的方向转变,这也将有助于解决诸如“加载更多”URL 包含之类的问题。
我脑海中设想的本质上是一个“分页”模块,它将规范化该模式,并能够在某些选定的端点中处理分页,或许可以从群组(Groups)开始。
我或许可以为这个功能提交一个 PR,但我想先提出这个问题供大家讨论。