RESTful 端点的输入 DTO 是否应与输出 DTO 匹配?

Should input DTOs for RESTful endpoints match the output DTOs?

我正在研究 RESTful API,我在思考向 API 提供输入的过程时遇到了一些麻烦。

假设我有一个 "Person" 资源可以像这样获取:api/person/{id} 和 returns 一个像这样的对象:

public class Person
{
    public int Id { get; set; }
    public string Surname { get; set; }
    public string GivenName { get; set; }
    public DateTime DateOfBirth { get; set; }
}

如果我想更新那个人,API 应该期待一个完整的 Person 实例,还是可以接受使用单独的 DTO?

假设 DateOfBirth 无法更改,是否认为 RESTful 接受此作为输入:

public class UpdatePersonDto
{
    public string Surname { get; set; }
    public string GivenName { get; set; }
}

这意味着我将在使用 GET 时将此端点 api/person/{id} returning Person,而在使用 [= 时接受输入 UpdatePersonDto 20=]。这对我来说听起来不对,但我不确定我是否只是偏执。

所以我想我的问题可以总结为:是否适合在给定资源端点上接受不同于端点 return 的数据结构?

似乎 REST 共识是当使用 PUT 更新时,提供整个实体来替换。

以编程方式,让 PUT /person/{id} 接受在幕后映射到 UpdatePersonDTO 而不是 Person 的输入。

唯一的'problem'可能是它确实违背了普遍预期。

中间解决方案可以是 POST(或 PUT)/person/{id}/mutables,它可以接受 UpdatePersonDTO。

编辑:或者更明显的是:PUT /person/{id}/name 它采用包含两个字段的 PersonName 参数。

当涉及到 REST 严格规则时(只要存在这样的规则:/),您应该将整个实体发送到 PUT。现在您可以:

  1. 静默忽略无法更新的字段 - 在某些情况下推荐使用,但应记录在案。
  2. 如果您检测到无法更新的字段被赋予了新值,则抛出异常。
  3. 而不是使用 PUT,使用 PATCH 可以更新一组字段,并且不需要整个实体,例如只能发送名字和姓氏。

我个人认为最好的选择是 1 或 3。我不建议按照@morsor 的建议引入新的端点。这样的端点总是会造成混乱。一般来说,端点越少越好(更干净,更容易理解)API。