PUT 是否应该始终能够插入?

Should PUT always be able to insert?

场景:

疑问与分疑问:

我是否应该始终允许客户端保存(放置)资源,即使它不存在(即在数据库中)?

可能性:

  1. 不行,这种情况下限制客户端保存动作比较合适。

    • 那么,哪个状态码适合响应 (400, 404)?
  2. 是的。 API 必须允许客户端使用 PUT 保存。

    • 那么,我应该如何处理 BobAlice 删除相同资源后立即保存一些更改的可能性?

您可以选择两者之一。如果选择前者,那么404比较合适

在开始 PUT 之前,让我们先看看 PUT 与 POST 的不同之处。

对 POST 的期望是 non-idempotent。这意味着使用完全相同的数据 多次调用 POST 可能会 导致与只调用一次不同的服务器状态。

对 PUT 的期望是它是幂等的。这意味着使用完全相同的数据多次调用 PUT 不应 导致与只调用一次不同的服务器状态。

让我们看几个例子:

POST 例子

假设一个 POST 请求被发送到 /person/add,其中包含一些数据以填充要添加的新人。第一次调用后,服务器将具有:

[
    { person: 0, ...data... }
]

(JSON 为简化示例而使用的语法)

现在,想象一下 完全相同的请求 再发生一三次:

[
    { person: 0, ...data... },
    { person: 1, ...data... },
    { person: 2, ...data... },
    { person: 3, ...data... }
]

在这个例子中,POST是非幂等的,同样的请求导致不同的服务器状态。

PUT 示例

现在假设一个 PUT 请求被发送到 /person/123,其中包含一些数据以更新 ID 为 123 的人。第一次调用后服务器可能有:

[
    { person: 0, ...data... },
    ...
    { person: 123, ...updated data... }
]

现在,想象一下 完全相同的请求 再发生一三次:

[
    { person: 0, ...data... },
    ...
    { person: 123, ...updated data... }
]

在此示例中,PUT 是幂等的,相同的请求会导致相同的服务器状态。

那么当这个人不存在时呢?

嗯,有两个选择:

  • 使用给定的 ID 创建 person 并填充其数据
  • return 404,因为找不到给定的用户

让我们看看处理请求的不同之处

创建人物

初始服务器状态:

[
    { person: 0, ...data... }
]

PUT /person/123 {...new data...}之后:

[
    { person: 0, ...data... },
    { person: 123, ...new data... }
]

多次PUT /person/123 {...new data...}后:

[
    { person: 0, ...data... },
    { person: 123, ...new data... }
]

此示例表明,当您从数据创建 person 时,这里对服务器状态没有真正的危害。

404 错误

初始服务器状态:

[
    { person: 0, ...data... }
]

PUT /person/123 {...new data...}之后:

[
    { person: 0, ...data... }
]

多次PUT /person/123 {...new data...}后:

[
    { person: 0, ...data... }
]

这个例子 表明,如果 person 不存在,当您发送错误时,对服务器状态没有真正的损害。

那么这一切意味着什么?

REST 不是必须严格遵守的严格定义的规范。它更像是 set of guidelines.

这意味着一切由您决定。

如果可以安全地从 PUT 请求创建新数据集并简化您的程序,那么允许它发生并没有什么害处,只要您执行所有与您希望的相同的验证和错误处理正在处理 POST 创建新对象的请求。

如果从 PUT 请求创建新数据集非常困难或无法安全地完成——例如当只有 一些 数据被更新时,并且服务器不能创建一个完整的对象——那么无论如何都不允许它并且return适当的错误代码(404 Not Found)。