I wanted to use Patch to update a single field on a large object in a .NET 4.6 Web API 2 project, and realised I’d somehow never implemented a Patch verb before (I know, right?). This seemed like the perfect time to learn.
I wasn’t sure of best practices for implementation in Web API 2, so I did the usual thing, and Googled things like “Patch Web API”. The first result I got was Michael McKenna’s “How to Add JSON Patch Support to Web API”. It looked like it made sense, but I wondered why he had to write a solution for this. Surely Patch in Web API is a fairly common requirement, and there’s a way to do this in a .NET recommended (if not native) way? Maybe Michael had it wrong.
After some digging, almost all the other forums and blog posts I found suggested one of three things, none of which I was happy with.
1. An API endpoint for setting every property
Some people recommended writing a method for every partial update: “set name for book”, “set page count for book” etc. Needless to say, this seems… incredibly time consuming to implement and maintain, especially if you have a lot of properties on the object in question, or several objects that need updating.
2. Using ODATA
A lot of forum responses suggest including the .NET ODATA library just to use its Delta classes for patch operations. This seemed a bit weird. ODATA is a whole different beast, compared to a simple JSON API. I think some areas of ODATA feel clunky, verbose and non-intuitive when held up against what we now talk about as API design best practices.
In addition, it sounds like there are problems with the ODATA library patching primitive types when used in a JSON Web API project, because the ODATA library is designed to work with the ODATA formatter, which is just different enough from the JSON formatter to be fun. It seems to be a lot of people using (or trying to use) ODATA to implement their JSON Patch actions, but it looks like it doesn’t work well at all.
3. Using a patch model with nullable properties
Let’s say we want to provide the ability to update the PageCount property on a book object. In the Book data model, Name is mandatory property, and there are other properties like Language, which are nullable. This proposed solution suggested creating a model for Book patching, with both PageCount and Name properties being nullable. If the property is supplied in the HTTP request, the value is set. If it is not supplied, the property is left unchanged, and if you want to clear the current value, you would supply the property with a null.
This didn’t seem tooo bad in a pinch, but could require extra logic to be written if non-nullable properties in the data model were passed as null in the Patch view model. It also required an extra Patch model for every data model which needed patch support, though that’s not the end of the world as create and update models already get created in many cases. Just a bit more to maintain.
This approach would also only let me set a property in a very simple way. If that property was an array, and I wanted to add a value to it, I’d have no choice but to essentially overwrite the entire array as part of the Patch operation. Or revert to writing a specific API method for each array operation I wanted to support. Surely there was a better way?
What is JSON Patch meant to look like?
ODATA was mentioned so often, but it seemed so wrong. Why should I have to use ODATA for a JSON Patch operation? What is the right way to do this? Aren’t there any standards for JSON Patch?
Turns out there is a standard for JSON Patch: standard RFC6902. Instead of a patch being an instruction to “set field x to this value”, patch should be an instruction – or set of instructions – to manipulate an object. A variety of operations are supported, like adding and removing array elements on the patched object, as well as setting properties on nested objects. ‘Replace’, ‘move’, ‘copy’ and ‘test’ operations are defined too. Interestingly, the ‘test’ function allows you to check if a property is equal to a value and looks useful.
JSON Patch looks a bit like this. If there is an object
{ "foo": "bar"}
and we want to add a property called “name” with a value of “Carly”, we’d send this HTTP Patch request with a body of:
[ { "op": "add", "path": "/name", "value": "Carly" } ]
And we’d get a response of:
{ "foo": "bar", "name": "Carly" }
Because JSON Patch expects a specific structure, it has its own MIME type: application/json-patch+json .
This resolves up a lot of concerns I had about other approaches, and feels more RESTful: the URI for our object would remain the same but our verb would change to include specific instructions for data manipulation, it was self descriptive, intuitive. It allows us to explicitly manipulate properties in a variety of ways, and offers the convenience of being able to make a range of changes to an object in a single action and manipulate array sets and nested properties. Wonderful!
Looking more closely at forum and blog posts, it looks like some of them advocating other approaches are posted before the JSON Patch standard was published in 2013, and some of them are just wrong, and are doing a disservice to learning developers. Big thanks go out to William Durant, and his blunt and informative post “Please. Don’t Patch Like An Idiot”, which drove the point home for me. I’m sure it doesn’t help that neither JSON Patch or XML Patch are supported in native .NET, or even illustrated in .NET Web API starter projects and blog posts. It’s a shame there’s still so much noise out there on this, much of it wrong, when in this case there is a right answer and a good approach.
How to Json Patch in .NET Web API 2
So now we know there is a right way to do JSON Patch, what’s the best way to implement it? The JSON standard was referenced in Michael’s post about JSON API – in the first line, even. And the purpose of Michael’s post was to introduce the JSON Patch library he’s written and released! So while it was valuable to go on that learning adventure and make sure I had the right answer, the solution was in the first blog post. How about that.
All you really need to do is:
- Nuget install: Install-Package JsonPatch -Version 1.0.0
- Add support for the MIME type and formatter
public static void ConfigureApis(HttpConfiguration config) { config.Formatters.Add(new JsonPatchFormatter()); }
- Implement your Patch method on your API Controller
public void Patch(Guid id, JsonPatchDocument<SomeDto> patchData) { //Remember to do some validation, error handling, and all that fun stuff var objectToUpdate = repository.GetById(id); patchData.ApplyUpdatesTo(objectToUpdate); repository.Save(objectToUpdate); }
That’s pretty much it. Your HTTP request to perform a patch would then look like this:
PATCH /my/data HTTP/1.1 Host: example.org Content-Type: application/json-patch+json [ { "op": "add", "path": "/a/b/c", "value": "foo" } ]
Moving Forward
It’s worth noting that the JSON Patch library has a few known issues and limitations. As always, decide for yourself if it’s appropriate to use with your project, and please contribute if you implement any fixes or added functionality.
Using Michael’s JSONPatch library, there are a few scenarios that might come up. One is preventing patch of specific properties, which should be fairly easy to solve with a custom attribute added to the data model.
At least it looks like there’ll be JSON Patch support in ASP.NET 5.
Hi Carly,
I am attempting to use the JSON Patch NuGet package in ASP.NET Core 1.0 (previously ASP.NET 5) from here: https://www.nuget.org/packages/Microsoft.AspNetCore.JsonPatch/
It seems though, that this is missing the JsonPatchFormatter that I need to add to my formatters when configuring the web API. Therefore, I get an HTTP 415 Unsupported Media Type.
Do you have any ideas that would point me towards a solution to this problem?
Hi Sam!
Ah, you’re suing the AspNetCore JsonPatch package, nice. I’ve not tried it yet, but I think Core’s MVC Json Formatter might be what you’re after? https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Formatters.Json/
The intro on that page says “ASP.NET Core MVC formatters for JSON input and output and for JSON PATCH input using Json.NET.” which sounds promising.
Good luck! Let me know how you go.
– Carly