2

假设我的模型是:

用户:

  • ID
  • 昵称

我有一个收藏/users/

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

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

{
  id: 123,
  nickname: 'someUserName'
}

这里没有什么花哨的。


在 /users/ 上发布

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

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

然后我的有效载荷变为:

{
  nickname: 'someUserName'
}

这合适吗?

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


获取 /users/id

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

{
  id: 123,
  nickname: 'someUserName'
}

放在 /users/id 上

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

但如果我这样做:

PUT /users/123

{
  id: 456,
  nickname: 'someUserName'
}

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

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


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

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

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

有人能帮我吗?:)

4

2 回答 2

5

首先,
如果您不使用 HATEOAS,它就不是 REST

我希望你明白这一点,我会在最后再谈。

在 /users/ 上发布

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

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

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

得到

完全有效

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

  1. 忽略有效载荷中的 ID
  2. 返回错误

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

总体问题

REST 在资源上运行。
/users/ 是资源集合的示例
/users/{id} 是单个资源的示例
您应该始终在每个响应中使用完全相同的表示。如果出于某种原因,更合适的做法是只给出信息片段,添加指向完整资源表示的元数据(链接)。
除了用户的第一个 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 在他开发 ZF2 REST 模块时在他的博客中写了一篇关于使用 HAL 的精彩总结(第一个条目是完全免费的 zf,仅解释 HAL)。

于 2013-06-06T14:39:03.727 回答
0

I'm interpreting your descriptions as saying that the id is not part of the resource, it's a unique identifier of the resource. In that case, it should not be part of the payload for any operation.

POST /users with payload {"nickname": "somebody"} would create a new resource with a URL returned in the Location header. That URL would presumably look like /users/123 but from the client's point of view there's no reason to expect that. It could look like /something/else/entirely.

GET /users/123 would (assuming that URL was returned by an earlier POST) return the payload {"nickname": "somebody"}.

PUT /users/123 would (with the same assumption as above) replace the resource with the payload you send with the PUT, say {"nickname": "somebody else"}.

If you want the client to be able to name a resource, then you'd also let PUT /users/123 create a new resource with that URL.

I know of no common RESTful way to rename a resource. I suppose a POST with the old URL as part of the query part or the body would make sense.

Now, suppose I'm wrong and you do want id to be part of the resource itself. Then every payload would include it. But from the client's point of view, there should be no assumption that "id": 123 implies that the URL would be /users/123.

Finally, all of this is from a fairly purist point of view. There is value to thinking of URLs as the only real identifier of a resource, but it's not awful to break that rule and have the client use logic to create the URLs.

于 2013-06-06T14:48:28.223 回答