>产品:PK = ProductId
> Part:PK = PartId
> ProductPartAssoc:PK =(ProductId,PartId)
产品可以有很多零件,零件可以是许多产品的组成部分。关联表还包含与协会本身相关的附加信息,而不是需要编辑。
我们有ProductsController和PartsController类,它们使用定义为{controller} / {id} / {action}的路由模板来处理通常的GET / PUT / POST / DELETE操作,以使以下IRI工作:
> GET,POST / api / Products – 返回所有产品,创建新产品
> GET,PUT,DELETE / api / Products / 1 – 检索/更新/删除产品1
> GET,POST / api / Parts – 返回所有零件,创建新零件
> GET,PUT,DELETE / api / Parts / 2 – 检索/更新/删除第2部分
> GET / api /产品/ 1 /零件 – 获取产品的所有零件1
> GET / api / Parts / 2 /产品 – 获取第2部分为组件的所有产品
我遇到麻烦的是如何定义ProductPartAssoc资源的路由模板。路由模板和IRI应该如何获取关联数据?
坚持约定,我会期待像:
> GET,POST / api / ProductPartAssoc – 返回所有关联,创建关联
> GET,PUT,DELETE / api / ProductPartAssoc / [1,2] – 检索/更新/删除产品1和第2部分之间的关联
我的同事发现这个审美感觉不好,似乎认为没有一个ProductPartAssocController类是更好的,而是添加附加的方法给ProductsController来管理关联数据:
> GET,PUT,DELETE / api / Products / 1 / Parts / 2 – 获取产品1和部件2之间关联的数据,而不是第2部分的数据作为第1部分的成员,这通常是基于其他我在其他地方看到的例子,如/ Book / 5 / Chapter / 3。
> POST没有线索,他们期望IRI看起来像什么。不幸的是,他们是决策者。
一天结束时,我想我正在寻找的是验证,或指向我可以指出,并说“看,这是别人做的。”
处理由复合键确定的资源的典型做法是什么?
解决方法
对于POST,您已经知道复合键。那么为什么不消除POST的需要,只需使用PUT来创建和更新?如果您的系统生成主键,则POST到集合资源URL非常好,但是如果您具有已知主键的组合,为什么需要POST?
也就是说,我也喜欢有一个单独的ProductPartAssocController包含这些URL的操作的想法。你必须做一个自定义的路线映射,但是如果你使用像AttributeRouting.NET这样很容易做的事情。
例如,我们这样做是为了管理角色中的用户:
PUT,GET,DELETE /api/users/1/roles/2 PUT,DELETE /api/roles/2/users/1
6个URL,但只有3个操作,全部在GrantsController中(我们将用户和角色之间的gerund称为“Grant”)。类最终看起来像这样,使用AttributeRouting.NET:
[RoutePrefix("api")] [Authorize(Roles = RoleName.RoleGrantors)] public class GrantsController : ApiController { [PUT("users/{userId}/roles/{roleId}",ActionPrecedence = 1)] [PUT("roles/{roleId}/users/{userId}",ActionPrecedence = 2)] public HttpResponseMessage PutInRole(int userId,int roleId) { ... } [DELETE("users/{userId}/roles/{roleId}",ActionPrecedence = 1)] [DELETE("roles/{roleId}/users/{userId}",ActionPrecedence = 2)] public HttpResponseMessage DeleteFromRole(int userId,int roleId) { ... } ...etc }
这对我来说似乎是一个相当直观的方法。将操作保持在单独的控制器中也使精简控制器成为可能。