Partial Entity Updates in WebAPI PUT/POST

♀尐吖头ヾ 提交于 2019-11-29 23:12:40

The best practice in API design is to use HTTP PATCH for partial updates. In fact, use cases like yours are the very reason why IETF introduced it in the first place.

RFC 5789 defines it very precisely:

PATCH is used to apply partial modifications to a resource.

A new method is necessary to improve interoperability and prevent
errors. The PUT method is already defined to overwrite a resource
with a complete new body, and cannot be reused to do partial changes. Otherwise, proxies and caches, and even clients and servers, may get
confused as to the result of the operation. POST is already used but without broad interoperability (for one, there is no standard way to
discover patch format support).

Mark Nottingham has written a great article about the use of PATCH in API design - http://www.mnot.net/blog/2012/09/05/patch

In your case, that would be:

  [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;
  }

Is this cool, or is there a pattern/practice that I haven't learned about yet that might facilitate partial updates by sending only what is needed over the wire?

A good practice of doing a POST or PUT is to only include values that you need for that specific request. In doing the UpdateDocument you should ask yourself what "really should be done here"? If you have a hundred fields on that object do you need to update all of them or only part of them. What "action" are you really trying to do?

Let's have an illustration for those questions, say we have a User object that has the following fields:

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;}
}

You then have two use cases:

  1. Update the profile of a User
  2. Update the password of a User

When you do each of those you will not, or it's a good idea to, have one update method that will do both. Instead of having a generic UpdateUser method you should have the following methods:

  1. UpdateProfile
  2. UpdatePassword

Methods that accepts fields that they just need, nothing more, nothing less.

public User UpdateProfile(int id, string username, string realname, string bio) {
}
public User UpdatePassword(int id, string password) {
}

Now comes the question:

I have a use case that a "user action" allows for an update on multiple fields where some of the fields can have "no input" from the user but I don't want to update that field in my model.

Suppose a user updates his/her profile and provided values for Username, RealName but not for Bio. But you do not want to set Bio as null or empty if it has a value already. Then that becomes a part of your application's business logic and that should be handled explicitly.

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;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!