【问题标题】:The REST-way to check/uncheck like/unlike favorite/unfavorite a resource检查/取消选中喜欢/不喜欢喜欢/不喜欢资源的 REST 方式
【发布时间】:2011-04-14 15:46:16
【问题描述】:

目前我正在开发一个 API,在该 API 中,我希望登录的用户能够喜欢/不喜欢或喜欢/不喜欢两个资源。

我的“Like”模型(它是一个 Ruby on Rails 3 应用程序)是多态的,属于两种不同的资源:

/api/v1/resource-a/:id/likes

/api/v1/resource-a/:resource_a_id/resource-b/:id/likes

问题是:我不确定选择哪种方式使我的资源尽可能地 RESTful。我已经尝试了以下两种方法来在我的 URL 中实现类似/不同的结构:

案例 A:(喜欢/不喜欢成为“资源”的成员)

PUT /api/v1/resource/:id/like maps to Api::V1::ResourceController#like
PUT /api/v1/resource/:id/unlike maps to Api::V1::ResourceController#unlike

和案例B:(“喜欢”是它自己的资源)

POST /api/v1/resource/:id/likes maps to Api::V1::LikesController#create
DELETE /api/v1/resource/:id/likes maps to Api::V1::LikesController#destroy

在这两种情况下,我已经有一个用户会话,所以我在删除/“取消喜欢”时不必提及相应“喜欢”记录的 id。

我想知道你们是如何实现这样的案例的!

2011 年 4 月 15 日更新:“会话”是指随每个请求发送的 HTTP 基本身份验证标头并提供加密的用户名:密码组合。

【问题讨论】:

  • 跟我想的一模一样!

标签: ruby-on-rails-3 api rest


【解决方案1】:

我认为您在服务器上维护应用程序状态(包含用户 ID 的用户会话)是这里的问题之一。它使这变得比它需要的要困难得多,并且它打破了 REST 的 无状态 约束。

在案例 A 中,您为操作提供了 URI,这又不是 RESTful。 URI 标识资源和状态转换应使用所有资源通用的统一接口执行。我认为案例B在这方面要好很多。

因此,考虑到这两点,我建议如下:

PUT /api/v1/resource/:id/likes/:userid
DELETE /api/v1/resource/:id/likes/:userid

我们还有一个额外的好处,即用户只能注册一个“赞”(他们可以多次重复该“赞”,并且由于PUT 是幂等的,因此无论如何它都具有相同的结果多次执行)。 DELETE 也是幂等的,因此如果由于某种原因多次重复“Unlike”操作,则系统将保持一致状态。当然你可以用这种方式实现POST,但是如果我们使用PUTDELETE,我们可以看到与这些动词相关的规则似乎非常适合我们的用例。

我还可以想象另一个有用的请求:

GET /api/v1/resource/:id/likes/:userid

这将返回“赞”的详细信息,例如创建日期或序数(即“这是第 50 次赞!”)。

【讨论】:

  • 嗨@joelittlejohn 和@jim-ferrans,我的错!我所说的“会话”实际上是 HTTP 基本身份验证,它使用 each 请求发送加密的用户名:密码组合并对用户进行身份验证。所以我在“喜欢”或“不喜欢”时总是有一个“current_user”,而且只有在执行操作时。凭据或身份验证不会保存在服务器端。从我的角度来看,它是无状态的。
【解决方案2】:

案例 B 更好,这里有一个来自 GitHub API 的很好的示例。

  1. Star a repo

    PUT /user/starred/:owner/:repo

  2. Unstar a repo

    删除 /user/starred/:owner/:repo

【讨论】:

    【解决方案3】:

    您实际上是在定义一个“喜欢”资源,即用户资源喜欢您系统中的其他资源。因此,在 REST 中,您需要选择一个唯一标识此事实的资源名称方案。我建议(以歌曲为例):

    /like/user/{user-id}/song/{song-id}
    

    然后 PUT 建立一个喜欢,然后 DELETE 删除它。 GET 当然会找出某人是否喜欢一首特定的歌曲。您可以定义GET /like/user/{user-id} 来查看特定用户喜欢的歌曲列表,并定义GET /like/song/{song-id} 来查看喜欢特定歌曲的用户列表。

    如果您假设用户名是由现有会话建立的,正如@joelittlejohn 指出的那样,并且不是类似资源名称的一部分,那么您就违反了 REST 的无状态约束并且您失去了一些非常重要的优势。例如,用户只能获得自己的赞,而不能获得朋友的赞。此外,它还破坏了 HTTP 缓存,因为一个用户的点赞与另一个用户的点赞无法区分。

    【讨论】:

    • @jim-ferrans 不幸的是,我需要将 url 的“/like”部分附加在 URL 的末尾,因为我想制作一个 ruby​​ gem 来“like/unlike”或“favor/不利”的事情。我希望能够将“acts_as_able”放入模型中。然后我想在 url 上附加一个相应的名词,例如“/likes”,并在它前面加上一个相应的 HTTP 动词,例如“DELETE”。但这有点离题。重点是:我希望将“/likes”部分附加到资源的末尾。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-06
    • 2018-05-27
    • 2022-08-03
    • 2022-12-13
    • 1970-01-01
    • 2014-03-30
    相关资源
    最近更新 更多