我有REST API实现遵循以下原则:rest只返回基本文档,并在那些文档中引用如何获取其他东西等等
例如/ car / 5会给我模型:blabla,user_id:1然后如果你需要拥有者你将获得/ user / 1来获取用户数据..
这样就可以避免在DB中使用JOINS和东西了。所有事情都是在它们之间进行链接和在休息客户端部分上互连的数据 - 保持简单易用,缓存/删除缓存,扩展等等。
但是当你需要排序时会发生什么?
想象一下,我们在前端有一些视图来显示以下数据: 汽车型号,用户名等......您想按用户名排序,例如。
你无法真正告诉/ car / 5按用户名排序,因为它只知道用户ID ...
我看到的一个选项是从用户/用户/列表中排序?sortby = username,然后互连其中哪些返回的ID实际上是指汽车。但这意味着我们需要获得所有用户......并且只使用那些似乎是杀手性能瓶颈的部分。
感谢您的任何指示
答案 0 :(得分:5)
我认为你试图避免加入所有错误的原因,因为采用这种方法,你将不得不服务更多的请求。
如果您改回了所有显示的信息(即加入数据库端),那么客户端将不得不减少查询次数,而可以进行排序无需(懒惰)加载所有子对象。
另一种选择是将子对象作为子XML元素返回(与OpenStreetMap的RESTful接口的工作方式类似)。您仍然可以从客户端获得一次点击,并且您应该能够优化查询以最大限度地减少数据库的负载。
答案 1 :(得分:4)
如果您要避免服务器中的所有连接并将其留给客户端,那么在这种情况下您必须将排序留给客户端。这是因为必须进行连接才能按用户名对汽车进行排序。
您可以创建另一个名为CarsAndOwners或类似资源的资源,它返回连接列表,此时在服务器上排序是合理的。
答案 2 :(得分:3)
我首先想象一下我想写的理想RESTful查询,例如:
/car/list?sortby=username
然后弄清楚如何实现它。
现在您的列表方法会为您提供 car 对象,但不会像您所说的那样公开用户名,但我认为不重要。在准备列表之前,所有排序都应该在服务器上进行。
为了做到这一点,您需要在某些时候将 car 对象加入用户对象,并且无法避开该问题。你唯一的选择就是你在哪里。
如果您正在使用传统的RDBMS,那么在数据库级别这样做是有意义的。
您是否在应用程序API和数据库之间使用了ORM层?
答案 3 :(得分:2)
首先,您的示例/car/5
应该是资源的复数版本才能成为RESTful:
/cars/5
/users/1
现在,一般来说,如果你想要一个RESTful方法进行排序,你可以这样做:
/cars?sort=make&order=asc
在您的示例中,您提到要按用户名对汽车进行排序。但是,正如您所提到的,cars
集合应该对users
一无所知。因此,如果您想显示汽车列表并按用户分组,您会怎么做?您需要一种方法来检索此信息。一种方法是循环用户并请求与每个用户关联的汽车:
# pseudo code
users.each do |user|
# assuming the user id is 5,
# to display the user's cars,
# we need to request /users/5/cars
end
因此,我们可以在/users/5/cars
这样的网址上为每个人请求汽车列表。这称为嵌套资源。我们只要求与用户5相关的汽车。
但是,您可能会向API提出大量请求(根据您的使用情况,这可能没问题)。
另一种可能更好的方法是在一个请求中执行此操作:
/users/cars?sort=username&order=asc
这将返回按用户名排序的用户及其汽车数组。
另一种方法可能是:
/users?include=[cars]&sort=username&order=asc
但我不像以前那样喜欢这种方法。我会推荐/users/cars
的先前方法。
附注:您的列表应该是分页的,这样当您只显示部分列表时,就没有{{1>}的所有的开销。
users
答案 4 :(得分:1)
数据库旨在快速进行连接,因此将其留给客户端或服务器应用程序对我来说没有意义。
我在REST上阅读的几乎所有内容都表明实体/资源之间的关系也应该是一种资源。因此,您应该有一个代表该连接/关系的资源/mydomain.com/CarsAndUsers。
然后你可以像对待任何其他资源一样对该资源进行排序,它将由数据库处理:
/mydomain.com/CarsAndUsers?sortby=username
您也可以像对待任何其他资源一样对该资源(和分页)应用过滤。
编辑:
根据评论,做这样的事情会更好:
/车?嵌入=用户,sortby =用户名
感谢Eric指出这一点。