什么是最好的RESTful方法来返回一个对象的项目总数?

我正在为我参与的一个大型社交网站开发一个REST API服务。到目前为止,它工作的很好。 我可以发出GETPOSTPUTDELETE请求来对象URL并影响我的数据。 但是,这些数据是分页的(一次只限于30个结果)。

然而,通过我的API来获取说,会员总数的最佳RESTful方法是什么?

目前,我向如下的URL结构发出请求:

  • / api / members – 提供成员名单(如上所述,每次30个)
  • / api / members / 1 –根据使用的请求方法影响单个成员

我的问题是:我将如何使用类似的URL结构来获取我的应用程序中的成员总数? 显然,只需要返回一个30分的结果,只需要inputid字段(类似于Facebook的Graph API)并计算结果就无效了。

当对/ API /用户的响应被分页并且只返回30个logging时,没有什么能阻止你在响应中包括总logging数和其他相关信息,如页面大小,页码/偏移量等。

StackOverflow API是同样devise的一个很好的例子。 以下是用户方法的文档 – https://api.stackexchange.com/docs/users

我更喜欢使用HTTP头来处理这种上下文信息。

对于使用X-total-count标题的元素X-total-count
链接到下一个,上一页等我使用http链接标题:
http://www.w3.org/wiki/LinkHeader

Github也是这么做的: https : //developer.github.com/v3/#pagination

在我看来,它更加干净,因为它可以用于返回不支持超链接的内容(即二进制文件,图片)。

另外,当你不需要实际项目

Franci Penov的回答肯定是最好的方式,所以你总是返回物品以及关于你的实体被请求的所有额外的元数据。 这是应该做的。

但有时候返回所有的数据是没有意义的,因为你可能根本不需要它们。 也许所有你需要的是有关你的请求资源的元数据。 像总数或页数或别的东西。 在这种情况下,您可以始终使用URL查询来告诉您的服务不要返回项目,而只需要如下的元数据:

 /api/members?metaonly=true /api/members?includeitems=0 

或类似的东西…

您可以将计数返回为自定义HTTP头以响应HEAD请求。 这样,如果客户端只需要计数,则不需要返回实际列表,也不需要额外的URL。

(或者,如果您处于从端点到端点的受控环境中,则可以使用自定义的HTTP动词,如COUNT。)

我最近一直在对这个和其他REST分页相关的问题进行一些广泛的研究,并认为在这里添加一些我的发现是有build设性的。 我正在扩大这个问题,包括分页的想法和计数,因为他们是明确相关的。

分页元数据以响应头的forms包含在响应中。 这种方法最大的好处就是响应负载本身就是实际的数据请求者所要求的。 对寻呼信息不感兴趣的客户更容易处理响应。

有一堆(标准和自定义)标题在野外使用返回分页相关的信息,包括总数。

X-合计数

 X-Total-Count: 234 

这用于我在野外发现的一些 API 。 还有一些NPM软件包用于将这个头文件添加到例如Loopback中。 一些文章也build议设置这个标题。

它通常与Link头结合使用,这是一个非常好的分页解决scheme,但缺less总计数信息。

链接

 Link: </TheBook/chapter2>; rel="previous"; title*=UTF-8'de'letztes%20Kapitel, </TheBook/chapter4>; rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel 

我觉得,从这个问题上读了很多,一般的共识是使用Link头提供分页链接到客户使用rel=nextrel=previous等。这个问题是,它缺乏多less信息总logging,这就是为什么许多API将它与X-Total-Count标题结合在一起。

或者,某些API和JsonApi标准使用Link格式,但将信息添加到响应信封而不是标题中。 这简化了对元数据的访问(并创build了添加总计数信息的地方),其代价是增加了访问实际数据本身的复杂性(通过添加信封)。

内容范围

 Content-Range: items 0-49/234 

由名为Range header的博客文章推广,我select你(分页)! 。 作者为使用RangeContent-Range标题进行分页提供了强有力的理由。 当我们仔细阅读这些头文件中的 RFC时,我们发现将它们的含义扩展到字节范围之外实际上是RFC所期望的,并且是明确允许的。 当在items而不是bytes的上下文中使用时,Range头部实际上给了我们一种方法来请求一定范围的项目并指示响应项目涉及的总结果的范围。 这个头也提供了一个很好的方式来显示总数。 这是一个真正的标准,主要是一对一地分页。 它也用在野外 。

信封

许多API,包括我们最喜欢的Q&A网站上的 API都使用一个信封 ,一个用来添加数据元信息的数据包装。 此外, OData和JsonApi标准都使用响应信封。

这个(imho)的一大缺点是处理响应数据变得更加复杂,因为实际的数据必须在信封的某个地方find。 信封也有很多不同的格式,你必须使用正确的。 这说明来自OData和JsonApi的响应信封是大不相同的,OData在响应中的多个点处的元数据中混合。

单独的终点

我认为这在其他答案中已经被覆盖了。 我没有调查这么多,因为我同意这个意见,这是令人困惑,因为你现在有多种types的端点。 我认为如果每个端点代表一个(资源集合)是最好的。

更多的想法

我们不仅要传递与响应相关的分页元信息,还要允许客户请求特定的页面/范围。 也有意思的是,这个方面最终会有一个连贯的解决scheme。 这里我们也可以使用标题( Range标题看起来非常合适),或者其他机制,比如查询参数。 有些人主张把结果页作为单独的资源来处理,这在某些使用情况下可能是有意义的(例如/books/231/pages/52 。我最终select了大量频繁使用的请求参数,如pagesizepage[size]limit等,除了支持Range头(以及作为请求参数)。

我会build议添加相同的标题,如:

 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" } ] 

有关详情,请参阅:

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

对于swagger文件:

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

那么刚刚调用Members.Count()并返回结果的新终点> / api / members / count呢?

似乎最简单的只是添加一个

 GET /api/members/count 

并返回成员的总数

有时框架(如$ resource / AngularJS)需要一个数组作为查询结果,而且在这种情况下,我不能将响应存储在responseHeaders中。

PS其实你可以做$ resource / AngularJS,但它需要一些调整。

在请求分页数据时,您知道(通过显式页面大小参数值或默认页面大小值)页面大小,因此您知道是否获取了所有数据作为响应。 当回应的数据less于页面大小的时候,你就得到了整个数据。 当一个完整的页面被返回,你必须再次要求另一个页面。

我更喜欢单独的终点计数(或与参数countOnly相同的终点)。 因为您可以通过显示正确启动的进度条来为最终用户准备长时间消耗的过程。

如果你想在每个响应中返回datasize,那么应该有pageSize,offset也被提到。 说实话,最好的方法是重复请求filter。 但是回应变得非常复杂。 所以,我更喜欢专用端点返回计数。

 <data> <originalRequest> <filter/> <filter/> </originalReqeust> <totalRecordCount/> <pageSize/> <offset/> <list> <item/> <item/> </list> </data> 

我的Couleage,更喜欢countOnly参数到现有的端点。 所以,如果指定了响应只包含元数据。

端点?filter=值

 <data> <count/> <list> <item/> ... </list> </data> 

端点?filter=值countOnly =真

 <data> <count/> <!-- empty list --> <list/> </data>