我目前正在开发一个具有多个模型对象的应用程序,这些对象之间有很多关系。
例如,我有一个用户对象和一个包含多个用户的组对象。
我们为这些对象公开的端点是:
/users
/users/{uid}
/users/{uid}/groups
/users/{uid}/groups/{gid}
/groups
/groups/{gid}
/groups/{gid}/users
/groups/{gid}/users/{uid}
到目前为止这很容易。现在让我们说每个用户和每个组都可以拥有设置,消息,头像...... ....
现在我们可以公开端点,例如
/users/{uid}/avatar
/groups/{uid}/avatar
/users/{uid}/messages
/users/{uid}/messages/{mid}
/groups/{gid}/messages
/groups/{gid}/messages/{mid}
/users/{uid}/settings
/groups/{gid}/settings
即使只有6个关系(用户 - >头像,群组 - >头像,用户 - >消息,群组 - >消息,用户 - >设置,群组 - >设置),RequestMappings的数量当我们考虑各种CRUD操作(PUT,DELETE,POST,GET,..)时,(端点)会大大增加
如果我添加另一个资源,例如可以包含多个组的groupOfGroups,我将公开的RequestMappings数量将呈指数级增长
/gog/{gogid}/groups
/gog/{gogid}/groups/{gid}
/gog/{gogid}/groups/{gid}/users
/gog/{gogid}/groups/{gid}/users/{uid}
/gog/{gogid}/settings
/gog/{gogid}/messages
/gog/{gogid}/avatar
我还要为CRUD操作添加RequestMappings。
为了避免代码重复,我一直在每个主控制器中使用catch all request mapping。例如,在UserController中,我将有以下requestMappings
GET /users
GET /users/{id}
POST /users
PUT /users/{id}
DELETE /users/{id}
/**
/ **映射会捕获/ users / {uid} / messages / {mid}调用。在/ **映射对应的方法内,我将执行以下操作
这会将请求转发到MessageController,我可以使用一些QueryDSL构建器来构建QueryDSL,只获取请求attrbitute中的任何内容的消息(在这种情况下,它是具有{uid}的用户,但它可以是一个id为{gid}的组或一个id为{gogid}
的groupOfGroups我想知道这是否是正确的解决方案,或者是否有更好的方式来处理关系而无需转发,但也无需重复代码。
至少在我看来,有三个终点是不合理的
/users/{uid}/messages
/users/{uid}/settings
/users/{uid}/avatar
检查用户是否存在,并且对group和groupOfGroups执行相同的功能,但唯一的区别是我们正在检查组是否存在或groupOfGroups是否存在。
重要的是要注意像Swagger这样的工具当然不支持这种方法,甚至转发,@ RestController也不能使用,只能使用更通用的web mvc注释@Controller。
我想知道最好的方法是遵循这里。
答案 0 :(得分:0)
在我看来,您正试图在URI路径中表示关系(或者也可能是导航)。 REST中的关系表示为链接,来自https://stackoverflow.com/a/6328171/1536382:
可以说一个团队有一个文档资源(/ team / {id} / players),这是团队中玩家(/ player / {id})的链接列表,玩家可以拥有一个文档资源(/ player / {id} / teams),是指该玩家所属团队的链接列表
REST不是关于URI的外观,而是关于向客户端发送指向某个州可用操作的链接(例如:如果我在我可以去{{1} })。只要服务器构建链接并且客户端只使用它们,链接的结构就不重要了。
但是,您的一些URI包含他们需要的更多信息(并且可能需要建立uri(而不是休息)的客户端知道它不需要知道的事情):{{1 }和/users/1
与/users/1/messages
相同,因为/gog/{gogid}/groups/{gid}/users/{uid}
始终可以检索用户的数据。
另一种可能性是/groups/{gid}/users/{uid}
实际上意味着"表示用户和组之间关联的资源"包括例如用户加入组的日期;如果是这种情况,那么对我来说这是一个新资源,例如:/users/{uid}
,有自己的ID,可以映射到{uid}
,/groups/{gid}/users/{uid}
可以重定向到它。会员资格将列在membership
/membership/{membership-id}
和/groups/{gid}/users/{uid}
可以重定向到/groups/{gid}/memberships
。如果共享头像,则在使用HTTP缓存时可能会有好处。