Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partial Entity Updates in WebAPI PUT/POST

Say you have a repository method to update a Document:

public Document UpdateDocument(Document document)
  {
  Document serverDocument = _db.Documents.Find(document.Id);
  serverDocument.Title = document.Title;
  serverDocument.Content = document.Content;
  _db.SaveChanges();
  return serverDocument;
  }

In this case, the entity has two properties. When updating a Document, both of these properties are required in the JSON request, so a request to PUT /api/folder with a body of

{
  "documentId" = "1",
  "title" = "Updated Title"
}

would return an error because "content" was not provided. The reason I'm doing this is because, even for nullable properties and properties that the user doesn't update, it seems safer to force the client to specify these fields in the request to avoid overwriting unspecified fields with nulls serverside.

This has led me to the practice of always requiring every updatable property in PUT and POST requests, even if it means specifying null for those properties.

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?

like image 672
SB2055 Avatar asked Apr 22 '13 00:04

SB2055


People also ask

Which HTTP method will perform partial update to a resource?

The HTTP PATCH request method applies partial modifications to a resource. PATCH is somewhat analogous to the "update" concept found in CRUD (in general, HTTP is different than CRUD, and the two should not be confused). A PATCH request is considered a set of instructions on how to modify a resource.

How do I update data in Web API?

Update operations use the HTTP PATCH verb. Pass a JSON object containing the properties you want to update to the URI that represents the record. A response with a status of 204 No Content will be returned if the update is successful.

What is the use of put method in Web API?

The HTTP PUT method is used to update an existing record in the data source in the RESTful architecture. So let's create an action method in our StudentController to update an existing student record in the database using Entity Framework. The action method that will handle HTTP PUT request must start with a word Put.

What is partial update?

A partial update is a change in the overall data set that does not require restarting the MDEX Engine. Partial updates allow you to update only those portions of the MDEX Engine index that have changed since the last baseline update. A partial update lets you implement a number of the source data changes.


2 Answers

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;
  }
like image 183
Filip W Avatar answered Sep 19 '22 05:09

Filip W


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;
    }
}
like image 32
von v. Avatar answered Sep 20 '22 05:09

von v.