【问题标题】:Can't understand some basic REST stuff无法理解一些基本的 REST 内容
【发布时间】:2013-06-06 14:09:52
【问题描述】:

假设我的模型是:

用户:

  • 身份证
  • 昵称

我有一个收藏/users/

我希望通过/users/{id} 而不是/users/${nickname} 检索用户,因为在一些更复杂的情况下,可能没有“逻辑唯一约束”。

因此,我可以使用的基本 JSON 有效负载为例:

{
  id: 123,
  nickname: 'someUserName'
}

这里没什么特别的。


发布到 /users/

据我所知,用户作为标识符。它是资源表示的一部分,因此它应该在有效负载 (?) 中。

如果我想自己在后端生成 ID 怎么办,例如使用 DB 序列?

那么我的payload就变成了:

{
  nickname: 'someUserName'
}

这样合适吗?

这个 POST 的输出应该是什么?没有?只是一个引用资源位置的标头,包括 ID?


获取 /users/id

当我们获取资源时,我们将其内容加载为 JSON:

{
  id: 123,
  nickname: 'someUserName'
}

PUT 到 /users/id

据我所知,此方法使用的有效负载应该“覆盖”资源内容。如果我们想要部分更新,我们会使用 PATCH。

但如果我这样做:

PUT /users/123

{
  id: 456,
  nickname: 'someUserName'
}

这是否意味着我们要更新资源的 id?

在 URI 和有效负载中都使用 id 是不是有点多余?


其实我真的不知道怎么处理id。

我不知道我是否应该在所有 POST / PUT / DELETE 操作中使用相同的资源表示。

我不知道 id 是否应该是唯一(?)资源表示的一部分。 但是如果 id 不是表示的一部分,那么当我列出用户时,使用 GET /users/,如果没有返回 id,那么我不知道客户端如何获取用户 id...

有人可以帮助我吗? :)

【问题讨论】:

    标签: api http rest


    【解决方案1】:

    首先
    不使用 HATEOAS 就不是 REST

    我希望你明白这一点,我会在最后回到那个。

    在 /users/ 上发布

    在 POST 有效负载中不使用 ID 完全可以。如果存在 ID,则会对错误消息做出反应,以便开发人员了解他们做错了。
    因此,如果您的用户资源中没有其他任何内容,则只有昵称作为有效负载是完全有效的

    你的服务器的输出应该包括三个重要的东西:

    1. HEADER:指示成功或失败的状态码(通常为201 Created)
    2. HEADER:新创建资源的位置(只是Location: /path/to/resource)
    3. BODY:已创建资源的表示。像 GET 一样返回完整的有效载荷!

    获取

    完全有效

    放

    您对 PUT/PATCH 的分析符合规范,新资源应该与有效负载相同,这意味着如果 ID 不同,用户希望更改它。如果有效负载包含不应更改的值(如 ID),您有两种可能性:

    1. 忽略负载中的 ID
    2. 返回错误

    在这两种情况下,都会告知用户您做了什么以及出了什么问题。我更喜欢发送/获取 400 Bad Request。如果特权用户可以更改 ID 但特定用户不能更改 403 Forbidden 可能更合适。 还要确保记录您的 API 行为。您可以允许在 API 中省略 ID。不要忘记以一致的方式处理 POST 有效负载中给出的 ID!

    总体问题

    REST 对资源进行操作。
    /users/ 是资源集合的示例
    /users/{id} 是单个资源的示例
    您应该始终在每个响应中使用完全相同的表示。如果由于某种原因,只给出一个信息的 sn-p 添加指向完整资源表示的元数据(链接)更为合适。
    除了用户的第一个 POST 请求之外,该 ID 始终存在。 POST 意味着资源的未来位置未知,必须由服务器提供。 这也意味着 GET /users/ 应该返回每个资源的 ID。

    一如既往地在 API 中返回严格并在请求中宽容。记录您的行为,以便用户学习。

    仇恨

    如果您实施 HATEOAS(超媒体作为应用程序状态的引擎),REST 的真正魅力就会显现。这部分意味着您应该使用有用的标签/链接组合来完善您的表示。这样客户就不必再构造一个 url。

    使用HAL 代表您的用户的示例如下:

    {
        "_links:" {
            "self": { "href": "http://yourrest/users/123" }
        },
        "id": "123"
        "nickname": "someUserName"
    }
    

    Matthew Weier O'Phinney in his blog when he developed a ZF2 REST Module 对使用 HAL 进行了很好的总结(第一个条目完全免费,仅解释 HAL)。

    【讨论】:

    • 很好的答案。我了解 HATEOAS 的好处,但随后您将“链接”添加到资源中。这很酷,但我想对于 id,我们应该注意客户端没有在 POST 上提供链接,或者在 PUT 上编辑它,对吧?
    • 在 HAL 中以“_”为前缀的所有内容都是元数据。客户端永远不能编辑元数据,它永远不是有效负载的一部分。如果客户提交元数据,请在您的处理中忽略它。如果您想友好(我建议)在您的回复中添加一条通知,说明元数据已被忽略,请不要将其发送给我们;)
    【解决方案2】:

    我将您的描述解释为 id 不是资源的一部分,它是资源的唯一标识符。在这种情况下,它不应成为任何操作的有效负载的一部分。

    POST /users 和有效载荷 {"nickname": "somebody"} 将创建一个新资源,并在 Location 标头中返回一个 URL。该 URL 可能看起来像 /users/123,但从客户的角度来看,没有理由期待它。它可能看起来像/something/else/entirely。

    GET /users/123 将(假设 URL 由较早的 POST 返回)返回有效负载 {"nickname": "somebody"}。

    PUT /users/123 将(假设与上述相同)将资源替换为您使用 PUT 发送的有效负载,例如{"nickname": "somebody else"}。

    如果您希望客户端能够命名资源,那么您还可以让PUT /users/123 使用该 URL 创建一个新资源。

    我不知道重命名资源的常用 RESTful 方式。我想将旧 URL 作为查询部分或正文的一部分的 POST 是有意义的。

    现在,假设我错了,您确实希望 id 成为资源本身的一部分。然后每个有效载荷都会包含它。但从客户端的角度来看,不应该假设"id": 123 暗示 URL 将是/users/123。

    最后,所有这些都是从一个相当纯粹的角度来看的。将 URL 视为资源的唯一真正标识符是有价值的,但打破该规则并让客户端使用逻辑来创建 URL 并不可怕。

    【讨论】:

    • 如果我不返回 id,GET /users/ 上的行为应该是什么?如果没有id,客户端如何删除从GET /users/中选择的用户
    • 对不起,REST 的全部目的是让客户端不构造 url。如果你这样做,你就不会在纯粹主义者的观点中使用 REST。
    • 我完全同意,如果 ID 仅用于后端目的,则它算作元数据,并且可以在资源表示中完全省略
    • GET /users/ 应该返回 URL 列表(可能还有其他数据),而不是 ID 列表。然后使用DELETE url删除选中的项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-28
    • 1970-01-01
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 2022-10-12
    • 1970-01-01
    相关资源
    最近更新 更多