来自RESTful API的分页响应有效负载

Cha*_*son 73 rest pagination

我想在我的RESTful API中支持分页.

我的API方法应返回产品的JSON列表/products/index.但是,可能存在数千种产品,我想通过它们进行分页,因此我的请求看起来应该是这样的:

/products/index?page_number=5&page_size=20
Run Code Online (Sandbox Code Playgroud)

但是我的JSON响应需要看起来像什么?API消费者通常会在响应中期望分页元数据吗?或者只是一系列必要的产品?为什么?

看起来Twitter的API包含元数据:https://dev.twitter.com/docs/api/1/get/lists/members(请参阅示例请求).

使用元数据:

{
  "page_number": 5,
  "page_size": 20,
  "total_record_count": 521,
  "records": [
    {
      "id": 1,
      "name": "Widget #1"
    },
    {
      "id": 2,
      "name": "Widget #2"
    },
    {
      "id": 3,
      "name": "Widget #3"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

只是一系列产品(没有元数据):

[
  {
    "id": 1,
    "name": "Widget #1"
  },
  {
    "id": 2,
    "name": "Widget #2"
  },
  {
    "id": 3,
    "name": "Widget #3"
  }
]
Run Code Online (Sandbox Code Playgroud)

cod*_*ion 95

ReSTful API主要由其他系统使用,这就是我将分页数据放在响应头中的原因.但是,某些API使用者可能无法直接访问响应标头,或者可能正在构建基于API的UX,因此提供一种方法来检索(按需)JSON响应中的元数据是一个优点.

我相信您的实现应该包括默认的机器可读元数据,以及请求时的人类可读元数据.如果您愿意,可以随每个请求返回人类可读的元数据,或者最好通过查询参数(例如include=metadata或)按需返回include_metadata=true.

在您的特定场景中,我将包含每个产品的URI和记录.这使API使用者可以轻松创建指向各个产品的链接.我还会根据我的分页请求的限制设置一些合理的期望.实现和记录页面大小的默认设置是可以接受的做法.例如,GitHub的API将默认页面大小设置为30条记录,最多为100条,另外还设置了查询API的速率限制.如果您的API具有默认页面大小,则查询字符串只能指定页面索引.

在人类可读的场景中,导航到时/products?page=5&per_page=20&include=metadata,响应可能是:

{
  "_metadata": 
  {
      "page": 5,
      "per_page": 20,
      "page_count": 20,
      "total_count": 521,
      "Links": [
        {"self": "/products?page=5&per_page=20"},
        {"first": "/products?page=0&per_page=20"},
        {"previous": "/products?page=4&per_page=20"},
        {"next": "/products?page=6&per_page=20"},
        {"last": "/products?page=26&per_page=20"},
      ]
  },
  "records": [
    {
      "id": 1,
      "name": "Widget #1",
      "uri": "/products/1"
    },
    {
      "id": 2,
      "name": "Widget #2",
      "uri": "/products/2"
    },
    {
      "id": 3,
      "name": "Widget #3",
      "uri": "/products/3"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

对于机器可读的元数据,我会在响应中添加链接头:

Link: </products?page=5&perPage=20>;rel=self,</products?page=0&perPage=20>;rel=first,</products?page=4&perPage=20>;rel=previous,</products?page=6&perPage=20>;rel=next,</products?page=26&perPage=20>;rel=last
Run Code Online (Sandbox Code Playgroud)

(链接头值应该是urlencoded)

... total-count如果您这样选择,可能还有自定义响应头:

total-count: 521
Run Code Online (Sandbox Code Playgroud)

在以人为中心的元数据中显示的其他分页数据对于以机器为中心的元数据可能是多余的,因为链接标题让我知道我在哪个页面和每页的数量,并且我可以快速检索数组中的记录数量.因此,我可能只会为总计数创建一个标题.您可以随时改变主意并添加更多元数据.

另外,您可能会注意到我/index从您的URI中删除了.一个普遍接受的约定是让您的ReST端点公开集合.有/index在年底muddies是略有上升.

在使用/创建API时,这些只是我喜欢的一些内容.希望有所帮助!

  • @MeV与任何基于游标的分页场景相同:总数将增加,如果最后一页已满,页面数量可能会增加,仅此而已.对于使用此类分页的每个应用程序,这是一种非常常见的情况.如果新产品出现在第一页或最后一页,它将取决于使用的排序. (3认同)
  • _“ReSTful API 主要由其他系统使用,这就是我将分页数据放在响应头中的原因”_ 这就像说外面阳光明媚,这就是我穿着蓝色衬衫的原因。是什么让您认为人类无法读取标题? (2认同)

小智 29

作为编写了几个用于使用REST服务的库的人,让我向您提供客户视角,了解为什么我认为将结果包装在元数据中是最佳选择:

  • 如果没有总计数,客户端如何知道它还没有收到所有内容并且应该继续在结果集中进行分页?在未执行下一页的UI中,在最坏的情况下,这可能表示为实际上不再获取任何数据的Next/More链接.
  • 在响应中包含元数据允许客户端跟踪较少的状态.现在我不必将我的REST请求与响应匹配,因为响应包含重建请求状态所需的元数据(在这种情况下,光标到数据集中).
  • 如果状态是响应的一部分,我可以同时对同一数据集执行多个请求,并且我可以按它们到达的任何顺序处理请求,这不一定是我发出请求的顺序.

并提出建议:与Twitter API一样,您应该使用直接索引/光标替换page_number.原因是,API允许客户端为每个请求设置页面大小.返回的page_number是客户端到目前为止请求的页数,还是给出最后一次使用的page_size的页面数(几乎可以肯定是后者,但为什么不完全避免这种歧义)?

  • 对于你的第一个项目,如果没有下一页,它是否是一个合适的解决方案来省略rel = next链接?对于您的第二个项目符号,该信息在客户端的响应中仍然可用,它不在响应的正文中,而是在标题中.你最后一段的+1. (8认同)

adn*_*ili 12

我建议为它添加标题.将元数据移动到标题有助于摆脱类似的包络result,data或者records响应主体仅包含我们需要的数据.如果您也生成分页链接,则可以使用链接标题.

    HTTP/1.1 200
    Pagination-Count: 100
    Pagination-Page: 5
    Pagination-Limit: 20
    Content-Type: application/json

    [
      {
        "id": 10,
        "name": "shirt",
        "color": "red",
        "price": "$23"
      },
      {
        "id": 11,
        "name": "shirt",
        "color": "blue",
        "price": "$25"
      }
    ]
Run Code Online (Sandbox Code Playgroud)

有关详情,请参阅:

https://github.com/adnan-kamili/rest-api-response-format

对于招摇文件:

https://github.com/adnan-kamili/swagger-response-template

  • 根据 RFC-6648,应在元数据键中删除“X-”前缀。 (3认同)
  • 虽然我已经支持 Ray 和你的评论和回答,但我建议不要删除“X-”,因为它完全令人困惑,我想“_哦,有这样的 HTTP 标头_?”我在 Google 上搜索了几分钟,直到我阅读了评论部分.RFC 很棒,但我认为约定也很重要。API 也是有版本的,因此如果有一天我们的自定义标头成为标准,我们只需在下一个版本中提供另一个标头。所以我建议添加“X-”回来了。 (3认同)