让我们假设我有一个对象,我在我的应用程序中公开为REST资源。此对象具有许多字段,并包含许多其他对象,包括关联的集合。像这样的东西,但想想更大:
Customer
List<Order> orders
List<Address> shippingAddresses;
// other fields for name, etc.
Order
List<Product> products
// fields for total, tax, shipping, etc.
Product
// fields for name, UPC, description, etc.
我在我的api中将客户公开为/customer/{id}
我的一些客户会希望每个订单中的每个产品都具有所有细节。如果我关注HATEOAS,我可以提供一个链接来获取产品详细信息。这将导致对服务的n + 1次调用以填充客户订单中的产品。另一方面,如果我总是填充它,那么许多客户端会收到一堆他们不需要的信息,我会进行大量不需要的数据库查找。
如何根据客户的需求允许客户代表我的资源?
我看到了一些选择。
使用Jackson的JsonView注释预先指定使用的内容。呼叫者要求提供适合他们的视图。即/customer/{id}?view=withProducts
。这将要求我在编译时指定所有可用的视图,并且不会那么灵活。
允许来电者要求在请求中填写某些字段,即/customer/{id}?fields=orders,firstName,lastName
。这需要我有一些处理程序可以解析fields参数,并可能使用反射来填充东西。听起来对我来说太乱了。您如何处理子资源。我可以做fields=orders.products.upc
并以这种方式加入收藏吗?听起来我正试图在REST之上编写hibernate。
关注HATEOAS并要求客户端进行一百万次HTTP调用以填充他们需要的内容。这对于那些不想在大多数时间内填充项目的人来说非常有用,但对于那些试图显示订单详细信息摘要或其他类似内容的人来说,这会很昂贵。
为每个视图分配资源......
其他
答案 0 :(得分:1)
我会做这样的事情: 的 /客户/ {ID} /命令/?包括=实体强>
这是您选项1的一种更具体的变体。
您还可以选择以下选项:
我倾向于避免使用单一资源,因为大多数时候或者最终有人总是想要一份事情清单。
答案 1 :(得分:1)
选项2(客户端指定字段)是一种过滤方法,更像是一个查询接口,而不是一个GETable资源。如果您接受服务将填充的POST请求中的部分模板,则您的过滤器可能会更具表现力。但这很复杂。
我愿意打赌你需要的是任何复杂实体的2个简单表示。这应该处理您域中99.9%的案例。鉴于此,再制作一些URI,每个URI一个&#34; view&#34;事情。
要处理0.1%的情况(例如,当您需要完全填充Products集合时),请为允许您过滤的嵌套实体提供查询接口。您甚至可以提供超媒体链接来检索这些集合,作为上述简化表示的一部分。