假设你有一个存储库的方法来更新文档:
public Document UpdateDocument(Document document)
{
Document serverDocument = _db.Documents.Find(document.Id);
serverDocument.Title = document.Title;
serverDocument.Content = document.Content;
_db.SaveChanges();
return serverDocument;
}
在这种情况下,该实体有两个属性。 当更新一个文件,这两种性质都需要在JSON请求,因此请求PUT /api/folder
与身体的
{
"documentId" = "1",
"title" = "Updated Title"
}
因为“内容”并没有规定将返回一个错误。 我这样做的原因是因为,即使是空的属性和属性,用户不更新,它似乎更安全强制客户端中,以避免覆盖与空服务器端未指定领域的要求,指定这些字段。
这导致我总是需要在PUT和POST请求的每个更新的财产,即使这意味着这些属性指定空的做法。
这是很酷的,或者是有一个模式/实践中,我还没有了解还可能方便必要的东西通过网络发送的部分更新?
在API设计的最佳实践是使用HTTP PATCH的部分更新。 事实上,使用像你这样的情况是,为什么IETF首先介绍了它的真正原因。
RFC 5789定义它非常精确:
补丁是用于局部修改应用到的资源。
一种新的方法是必要的,以提高互操作性和预防
错误。 PUT方法已经被定义来覆盖资源
具有完整的新机构,而不能再用做局部修改 。 否则,代理和缓存,甚至客户端和服务器,可以得到
困惑,所述操作的结果。 POST已被使用,但没有广泛的互操作性(为一体,没有标准的方式来
发现补丁格式支持)。
马克诺丁汉写关于API设计中使用PATCH的大文章 - http://www.mnot.net/blog/2012/09/05/patch
在你的情况,这将是:
[AcceptVerbs("PATCH")]
public Document PatchDocument(Document document)
{
Document serverDocument = _db.Documents.Find(document.Id);
serverDocument.Title = document.Title;
serverDocument.Content = document.Content;
_db.SaveChanges();
return serverDocument;
}
这是很酷的,或者是有一个模式/实践中,我还没有了解还可能方便必要的东西通过网络发送的部分更新?
做的好的做法POST
或PUT
是只包括您需要的特定要求值。 在做UpdateDocument
你应该问自己什么是“真应该在这里完成”? 如果你有一百个字段对象上你需要更新所有的或只是其中的一部分。 什么“动作”你真的想要吗?
让我们对这些问题的一个例证,说我们有一个User
具有以下字段的对象:
public class User {
public int Id {get;set;}
public string Username {get;set;}
public string RealName {get;set;}
public string Password {get;set;}
public string Bio {get;set;}
}
然后,您有两个用例:
- 更新用户的配置文件
- 更新用户的密码
当你每次那些你不会,或者这是一个好主意,有一个更新的方法,将两者都做。 相反,有一个通用的UpdateUser
方法,你应该有以下几种方法:
-
UpdateProfile
-
UpdatePassword
方法接受,他们只需要领域,仅此而已,无所不及。
public User UpdateProfile(int id, string username, string realname, string bio) {
}
public User UpdatePassword(int id, string password) {
}
现在问题来了:
我有一个使用案例,一个“用户行为”允许在多个领域的更新,其中一些字段可以由用户“无输入”,但我不想更新我的模型场。
假设一个用户更新他/她的个人资料和提供的值Username
, RealName
而不是Bio
。 但你不希望设置Bio
为null或空,如果它有一个值了。 那么它将成为您的应用程序的业务逻辑的一部分,并应明确处理 。
public User UpdateProfile(int id, string username, string realname, string bio) {
var user = db.Users.Find(id);
// perhaps a validation here (e.g. if user is not null)
user.Username = username;
user.RealName = realname;
if (!string.IsNullOrEmptyWHiteSpace(bio)) {
user.Bio = bio;
}
}