我正在尝试设计一个基于REST-ish的Web服务,以便与我正在开发的农场动物管理系统进行交互。
为了详细解释这个问题,我有一个属于农场的动物的集合。每只动物都有自己的信息 - 例如姓名,身份证号码,品种年龄等。因此,我会假设以下的URI适合:
/animals <- retrieve list of animals
/animals/{animal-id} <- Retrieve only one animal
/animals?breed=sheep <- Search/query
当我尝试将其他相关资源链接到每只动物时,问题就出现了。动物可以拥有重量信息的集合,以及我称之为评论(针对特定动物的观察)。这些中的每一个都是依赖的,只存在于一个特定的动物中,但它们本身就是我想要访问的资源。
IMO最简单的方法是将资源嵌套在动物URI中:
/animals/{animal-id}/weights
/animals/{animal-id}/comments
但是,我发现需要直接访问和查询权重和注释,而无需引用动物。使用的示例是从特定品种...?breed=sheep
的所有动物中检索最近(或所有)重量,或甚至为选择的个体动物ID ...?animals={ID1},{ID2},{...}
返回权重/评论。 / p>
当我想一次向多个动物添加一条评论时,会出现更多复杂情况。 (请原谅我对POST和JSON的陈述)
POST ....
{
"comment":"Animal moved to paddock B",
"animals":[{id1}, {id2}, ...]
}
我知道这个问题的明显解决方案是GET和POST(例如)到我想要检索/编辑的每个动物。我宁愿不这样做,因为最终我希望从移动设备访问这项服务,因此减少通话次数似乎是明智之举。
我相信网络标准允许在URI中使用CSV,因此这样的事情可以起作用,
/animals/{id1},{id2},{..}/weights
但是,我期待一次(或查询)需要引用十(10)只动物的情况,这会导致一个混乱且不友好的URI。
我目前认为的解决方案是将权重和注释作为自己的资源公开,这样我就可以直接访问和查询
/weights
/weights/{weight-id}
/weights?breed=sheep
甚至直接发布到集合
POST /comments
{
"comment":"Animal moved to paddock B",
"animals":[{id1}, {id2}, ...]
}
但/animals/{animal-id}/weights
会返回什么?它是否需要,或者我只是引用/weights?animal={animal-id}
资源本身的链接?但链接到查询资源是否可以?
我是在制作一个多余的,还是只提供“另一种”方式来访问信息?
有什么我做错了,我让我的数据库影响我的服务模式,还是我完全忽略了这一点?
我对此很陌生,并且已经阅读了很多关于这些问题的矛盾论点,所以对于什么对我的要求最好是很困惑。
谢谢!
答案 0 :(得分:3)
如果您希望为其他实体解决这些资源(/weights
,/comments
等),最好为其他实体定义顶级资源。然后,您可以批量方式POST到这些端点。
POST /comments
{
"animals" : [
{"id" : 1},
{"id" : 2},
{"id" : 3},
{"id" : 4},
],
"commentText" : "Sent to Hamburger Hamlet"
}
请注意,由于多种原因,在您的网址中包含长ID列表并不是很好的设计,包括大多数浏览器和HTML代理都对网址长度有限制(好的经验法则是尝试将网址长度保持在2083个字符以内)长度或更短)。
答案 1 :(得分:1)
我遇到了类似的问题,但最终我们能够通过使用API为不同的用户类型提供特定的URL名称空间(可以这么说)来消除您所获得的复杂性。
例如,它可能是一个农场工人客户端应用程序,它将执行您正在描述的/ weight,/ comments操作(POST,PUT,DELETE等),因此您可以通过以下方式保持其功能清洁:
/farmworkers/comments
/farmworkers/weights
然后仍将/animals/{animal-id}/weights
网址保留在其他“命名空间”中。
要考虑的另一件事是使用类似HAL格式(http://stateless.co/hal_specification.html)的内容来嵌入资源,这可以允许您在请求中嵌入多个动物资源等。希望这会有所帮助。