RESTPOST提供ID怎么办?

What to do when REST POST provides an ID?

我正在开发一个 JAX-RS API,它包括一个简单的 "Person" table 和字段 "id" 和 "name",其中 "id" 与 mysql 数据库中的自动编号相关联。一个典型的用例是 POST 一个新人。

JSON 消息 {"name":"Bob"} 的 POST 可能 return,例如 {"id":101,"name":"Bob"}.

如果调用者请求 POST 包含标识符的对象怎么办?看来我的选择是:

从安全角度来看,最后一个选项似乎不太可靠。如果我使用 mysql,恶意用户可能会在一次请求中将我的自动编号增加到最大值。

如何在 REST API 中处理 POST 请求中包含的 ID?

您绝对应该拒绝所有到达 /users/ 端点的请求。首先出于安全原因(在数据库级别),其次这不是客户端 generate/suggest ID 的工作。

所以答案是拒绝无效请求以及适当的状态代码 (400) 和解释拒绝原因的消息。

第二个选项是不直观的,它正在发送 ID(正如我所写的那样,这是一个坏主意)- 预计不会收到它发布的不同 ID。在正文中发送 ID,对于 PUT 请求是有意义的,它假定对象已经是 created/existing - 这是一个更新。

第三个选项不会是 RESTful - REST 中没有更新插入 - POST 创建新资源。第四个选项根本没有意义 - 这不是客户提供 ID 的工作。

另一种选择是使用@JSonIgnore 注释忽略它。在 GET、PUT 或 DELETE 上,您将拥有 /user/{id},因此客户端应该已经知道 ID。在 POST 上,客户端不应发送 ID,您应该 return ID,或者更确切地说,URL 您可以获取创建的对象,其中包括编号.

真正归结为您希望 API 支持的内容。

允许创建但也允许替换

PUT /users/101 发送请求意味着您允许客户端 替换 或使用提供的负载创建 ID 为 101 的资源。根据数据库的响应,对此的正常响应是 return 200(如果导致替换)或 201(如果导致插入)。 请注意,这是一个 replace 类型的更新,而不是部分更新。如果您只需要更新资源的一部分,那么您正在寻找在 RDBMS 中很难实现的 PATCH。

如果您不想要该行为,则不允许该动词

如果您不想支持这种行为,那么最好的办法就是根本不允许该路由使用 PUT 动词。这是 RESTful 要做的事情。如果您实施了 HATEOS(实际上是什么 RESTful),那么 PUT 动词将不会出现在响应负载的超媒体 link 中,并且 return HTTP 405 方法不会如果您仍然尝试使用它,则允许。

你真的是RESTful吗?

如前所述,您可以不允许 ID 并要求它位于 body 中,但这不是必需的,实际上也不会很 RESTful。我的意思是——通过 HATEOAS 的镜头来看它。很容易争辩说,如果客户端需要知道 ID 应该在 PUT 的 body 中(甚至可能是 ID 的名称,例如,如果您将其称为“UserID”),那么这基本上忽略了超媒体的整个目标,在这个目标中,客户不需要真正了解 API 来导航它。也就是说,基本上没有人实施 HATEOAS/Hypermedia,但是当试图争论什么是什么不是 RESTful 时,这就是你的指路明灯 IMO。在真正的RESTfulAPI中,客户端只需要知道资源路径和被操作的实体的形状。

关于 client-provided 资源 ID 的问题是,人们试图提出他们不可能知道整数身份中的下一个数字的论点。我要说的是——嗯..那是你的问题。看在上帝的份上,请停止使用 PK 作为您的 public ID。实体 ID 应该是全局唯一的,因此让客户端生成一个 GUID 以供使用,例如,或者在您的服务器端为 POSTs 执行此操作。将其用作您的“应用程序实体 ID”。那应该是您在应用程序之间传递的 ID。你可以整天争论性能,但是 a) 在像 MongoDB 这样的数据库中几乎没有明显的影响,在 RDBMS 中几乎没有任何明显的影响,并且 b) 你没有 link 表和应用程序 ID -- 这是一个 where 子句。您仍然在数据库端使用数据库 IDs/PKs,只是不要将其泄漏到野外。但无论如何...

当您想创建一个新资源并且不允许客户端设置ID时

因此,如果您的意图是允许客户端创建资源,则使用 POST。为此,不应在路由中提供 ID(例如 POST /users/101),因为这没有多大意义。如果您需要允许他们设置 ID,请按上述方法实施 PUT。如果成功,POST 的正确响应是 201 Created,并包含 Location header 以便客户端执行 GET 以检索其新资源。事实上,有一个称为“PRG”(Post-Redirect-Get) 的模式,其中您 return 一个 303 See Other 将为您解决这个问题。这在 web/front-end 上下文中效果最好,但如果客户端将 auto-follow 重定向,也可以与 Client-API 一起使用。或者,您可以简单地使用 return 201 body 中的新资源和填充的新 ID。