RESTful API设计:在创建多对多关系时,使用PUT还是POST?

4
设计和创建RESTful API时会遇到以下问题:
API支持GET(用于查询),POST(用于创建),PUT(用于更新)和DELETE(用于删除)。
假设在数据库中已经存在一个文章和一个商店实例。
现在我们需要一个rest调用来将文章实例链接到商店实例。以下哪种解决方案是最好/最干净的REST设计:
1. /shop/id/article/id/ --> 使用POST 2. /shop/id/article/id/ --> 使用PUT 3. /shoparticlerelation/ --> 使用POST(对象在正文中具有ID) 4. /shoparticlerelation/ --> 使用PUT(对象在正文中具有ID)
如果没有明确的答案或所有解决方案都同样好,如果有明确的论证,这也可能是一个有效的答案。

1
在简单的英语中,文章和商店之间有什么关系? - Tim
多个商店和多个商品 - 每个商品可以在每个商店销售,但前提是它必须连接。 - Blackbam
2个回答

5
我猜测在这种情况下,你已经有了一组“店铺”和一组“文章”,而你只是想把它们联系起来。
一种选择是暴露一个类似于数据库的“资源”,展示这种链接,并有像操作一样的功能。
POST /shopArticleLinks HTTP/1.1

{ "shop"  : xxx,
  "article: YYY
}

我会建议将其作为商店和/或文章的属性以更自然的方式展示,例如:
PUT /shop/<ID> HTTP/1.1

{ /* existing details */
  "articles": [ /* list of articles */ ]
}

我在那里使用了JSON,但当然您可以使用任何格式。我也坚持使用PUT,但请记住,使用PUT时应发送新修改版本的完整替换,PATCH可用于发送部分更新,但然后您需要考虑如何做到这一点,可能是类似于

PATCH /shops/<ID>/articleLinks HTTP/1.1

{ "add"   : [],
  "remove : []
}

不要忘记,在服务器端您可以查看正在引用的文章articles并确保它们有适当的回指针。

其他想法

关于第二种方法,您将链接公开为shop和/或article资源的属性。请记住,当您更新给定shop中的链接时,相应articles中的链接也会被更新,这是非常适当的。


1
听起来可行,但是仅为了链接两个资源而创建一个新资源是通往设计模式所称的“类爆炸”的一步。 - Tim
是的,这绝对不是我会选择的选项。虽然它确实反映了在数据库中存储的方式,但这忽略了REST的“表现层”部分。 :P - thecoshman

1

/shop/id/article/id/

您不能使用此链接,因为在您想要将它们链接在一起的时候,这个端点还不存在(或者至少不应该存在)。链接它们在一起的操作应当定义此端点。

/shoparticlerelation/

您不应该使用此链接,因为 shoparticlerelation 不是资源/实体。通常情况下,在 REST 架构中,每个命名的 URL 段表示可以进行 CRUD 操作的资源。例如,/shops/articles 都是很好的例子,但这个链接不是。
我建议如下:
定义以下端点
/shops 用于 POST 新商店 /shops/id 用于操作单个商店 /articles 用于 POST 新文章 /articles/id 用于操作单篇文章
然后,要将它们链接在一起,您可以进行所谓的 PATCH 请求,以更新商店的文章或文章的商店:
PATCH /shops/1 HTTP/1.1

{
    "attribute": "articles",
    "operation": "add",
    "value": "8" // the article id
}

并且

PATCH /articles/9 HTTP/1.1

{
    "attribute": "shops",
    "operation": "add",
    "value": "1" // the shop id
}

根据您的评论,我假设一个Article模型具有商店列表作为属性,反之亦然,这种方法是有效的。
使用PATCH请求来指定如何和什么更新已存在的资源。这与PUT不同,因为PUT用请求中的值替换整个资源,但PATCH仅用于修改(而不是替换)资源。

我会支持你建议使用PATCH,但是这个建议被使用两个请求来执行同一个操作所抵消了。 - thecoshman
@thecoshman 我建议用两个补丁请求的方式将它们链接在这里。无论您是通过哪个资源进行修补,我都可能会在同一个请求中以两种方式链接它们。 - Tim
啊,我明白了,基本上就是我建议的,只是没有那么明确地表达出来。 - thecoshman
1
“您不能使用此功能,因为在您想要链接它们的时候,此端点尚不存在(或者至少不应该存在)。” 这不是一种品味和决定资源关系何时存在的方式吗? 对我来说,如果 shopidarticleid 本身存在,则 /shops/shopid/articles/articleid 也始终可以存在。 对此资源进行 GET 操作默认情况下将返回 {linked: false}。 使用 PUT 可以更新 linked 属性以添加或删除商店中的文章。 - JHH
“shoparticlerelation不是资源/实体” - 不同意。从REST的角度来看,这种关系可以被视为一种资源。您可以列出这些资源,创建/更新/删除它们。现在,这个关系只有两个ID(shop_idarticle_id)在它的主体中。将来,您可能会添加更多属性,例如created_at(关系创建时间),expires_at等。 - Dalibor Filus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接