RESTful API 设计:CRUD 轻量级连接的最佳方式? [英] RESTful API design: best way to CRUD lightweight connections?

查看:28
本文介绍了RESTful API 设计:CRUD 轻量级连接的最佳方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(请原谅问题标题;很难概括这个问题.)

在 Facebook,您喜欢 的东西.在 Twitter 上,你关注人.在 GitHub 上,您还关注人和star存储库和要点.

所有这些情况都非常相似:这些连接都是轻量级的,而不是真正的资源"本身.例如.这三个 API 都没有公开此类连接的公共 ID.

这就提出了一个问题:公开用于创建/查询/删除这些连接的 API 的最佳"(就 REST 而言)方式是什么?

<小时>

Facebook [1]:>

  • GET/:id/likes 查询对象的喜好(更准确地说,是喜欢该对象的用户)

  • POST/:id/likes 点赞(代表授权用户;不需要请求体)

  • DELETE/:id/likes 不喜欢某物(代表已授权用户)

查询和创建是有道理的,但 DELETE 有点unRESTful",因为您实际上并没有删除 /:id/likes 资源(一个喜欢该对象的用户数组).

这种差异体现在另一个案例中 [2]:

  • GET/me/likes/:id 查询你是否喜欢某样东西

因此查询您的连接是查询与创建或删除它完全不同的资源.

<小时>

GitHub 倾向于使用 /me/likes/:id 样式来关注用户并为 repos 加注 [3]:

(注意 GitHub 的 /user 代表授权用户,就像 Facebook 的 /me.)

  • GET/user/starred/:owner/:repo 用于查询您是否有已加星标的存储库(返回 204 或 404,两种方式都没有正文)

  • PUT/user/starred/:owner/:repo 用于为 repo 加注星标(请求中不需要正文)

  • DELETE/user/starred/:owner/:repo 用于取消 repo 的星标

这更加一致,但不幸的是,这将单个明星"与群体分开:

  • GET/repos/:owner/:repo/stargazers 查询给 repo 加星标的用户
<小时>有趣的是,

GitHub 使用不同的风格来主演 gists [4]:

  • GET/gists/:id/star 用于查询您是否有 gist 加星标

  • PUT/gists/:id/star 用于标注要点

  • DELETE/gists/:id/star 用于取消 gist 的星标

这会使用要点资源(例如 Facebook)而不是用户资源来保持加注操作.

GitHub 不会公开gists' 观星者,但大概是例如:

  • GET/gists/:id/stargazers 查询给 gist 加注星标的用户

虽然stargazers"确实是与star"不同的资源/名称,但名称相似且明显相关,并且它们都位于同一资源上.

我能想到的唯一缺点是命名资源.star 之类的东西有效,但 followlike 之类的操作比较棘手.

<小时>

(不打算以 Twitter API 为例,因为它几乎不是 RESTful.)

显然没有完美的 RESTful API 来创建/查询/删除不合适的资源,但还有其他我没有看到的优点/缺点,或其他需要考虑的风格吗?

谢谢!

解决方案

我喜欢 /me/likes/:id 风格的一件事是喜欢 do感觉像是个人的、可寻址的资源——例如他们有个人 ID(恰好和我喜欢的东西一样).

GitHub 的 repo API 很好地使用它来创建/查询/删除到 repos 的星"连接,但是获取给定的所有星"连接存在差异回购.

也许可以通过更改处理这些连接的方式来解决差异:不要仅仅依赖于对象 ID,也可以使用(经过身份验证的)用户 ID.例如:

  • GET/:owner/:repo/stargazers 查询所有给这个 repo 加星标的用户

  • GET/:owner/:repo/stargazers/:id 以查询用户 :id 是否已为 repo 加星标 -- 这可以是 auth'通过指定 me!

  • 来编辑用户
  • PUT/:owner/:repo/stargazers/me 为 repo 加注星标 -- 这仅适用于经过身份验证的用户

  • DELETE/:owner/:repo/stargazers/me 取消对 repo 的注视 -- 同上

现在所有的资源/动作都放在一起,动作一致,命名也很容易.

编辑:这种方法的另一个好处是,您可以轻松有效地查询其他用户是否也喜欢/关注/加注某个对象.

但缺点是资源在技术上不再正确——GET .../stargazers 返回一个用户列表,但是 GET .../stargazers/:id 返回一个连接,而不是一个用户.哦,好吗?

[再次编辑以支持在此处将 me 作为 :id 传递.]

(Pardon the question title; hard to summarize this question.)

On Facebook, you like things. On Twitter, you follow people. On GitHub, you also follow people and star repos and gists.

All of these cases are pretty similar: those connections are lightweight, not really "resources" themselves. E.g. none of those three APIs expose public IDs for such connections.

This raises the question: what's the "best" (in terms of REST) way to expose an API for creating/querying/deleting those connections?


Facebook does [1]:

  • GET /:id/likes to query an object's likes (more precisely, the users that like that object)

  • POST /:id/likes to like something (on behalf of the auth'ed user; no req body needed)

  • DELETE /:id/likes to unlike something (on behalf of the auth'ed user)

The querying and creating make sense, but the DELETE is a bit "unRESTful", because you're not actually deleting the /:id/likes resource (an array of users that like that object).

This discrepancy shows itself in another case [2]:

  • GET /me/likes/:id to query whether you like something

So querying your connection is querying a totally different resource than creating or deleting it.


GitHub leans to the /me/likes/:id style for following users and starring repos [3]:

(Note that GitHub's /user represents the auth'ed user, like Facebook's /me.)

  • GET /user/starred/:owner/:repo for querying whether you have a repo starred (returns 204 or 404, no body either way)

  • PUT /user/starred/:owner/:repo for starring a repo (no body needed in request)

  • DELETE /user/starred/:owner/:repo for unstarring a repo

This is much more consistent, but unfortunately this separates individual "stars" from the group:

  • GET /repos/:owner/:repo/stargazers to query the users who've starred a repo

GitHub, interestingly, uses a different style for starring gists [4]:

  • GET /gists/:id/star for querying whether you have a gist starred

  • PUT /gists/:id/star for starring a gist

  • DELETE /gists/:id/star for unstarring a gist

This keeps the starring action with the gist resource, like Facebook, rather than the user resource.

GitHub doesn't publicly expose gists' stargazers, but presumably it'd be e.g.:

  • GET /gists/:id/stargazers to query the users who've starred a gist

While "stargazers" is indeed a different resource/name than "star", the names are similar and clearly related, and they're both on the same resource.

The only downside I can think of to this is naming the resource. Something like star works, but actions like follow or like are trickier.


(Not bothering to include the Twitter API as an example since it's hardly RESTful.)

There's clearly no perfectly RESTful API for creating/querying/deleting things that aren't proper resources, but are there other pros/cons I'm not seeing, or other styles to consider?

Thanks!

解决方案

One thing I liked about the /me/likes/:id style is that the likes do feel like individual, addressable resources -- e.g. they have individual IDs (that happen to be the same as the things I'm liking).

GitHub's repo API uses this nicely for creating/querying/deleting "star" connections to repos, but there's a discrepancy for fetching all "star" connections for a given repo.

Perhaps the discrepancy could be addressed by changing the way you address these connections: instead of relying solely on the object ID, use the (auth'ed) user's ID too. E.g.:

  • GET /:owner/:repo/stargazers to query all the users who've starred this repo

  • GET /:owner/:repo/stargazers/:id to query whether user :id has the repo starred -- this can be the auth'ed user by specifying me!

  • PUT /:owner/:repo/stargazers/me to star a repo -- this'll only work for the auth'ed user

  • DELETE /:owner/:repo/stargazers/me to unstar a repo -- ditto

Now all the resources/actions are together, the actions are consistent, and naming is easy.

Edit: Another benefit of this approach is that you can easily and efficiently query whether other users like/follow/star an object, as well.

Edit: But a downside is that the resources aren't technically correct anymore -- GET .../stargazers returns a list of users, but GET .../stargazers/:id returns a connection, not a user. Oh well?

[Edited again to support passing me as the :id here too.]

这篇关于RESTful API 设计:CRUD 轻量级连接的最佳方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆