I am interested in adding support for partial updates in my ASP.NET Core WebAPI where I only update the properties on a resource that the caller provided, leaving excluded properties unchanged.
For context, imagine I have a resource that can be described as follows:
GET /users/1
{
title: "Mister",
firstName: "Frederick",
middleName: "McFeely",
lastName: "Rodgers"
}
If I wanted to allow consumers to change the value stored in the firstName
property from "Frederick" to "Fred" in isolation, I should be able to expose a PATCH
endpoint that supports the JSON Merge Patch Content-Type
, like so:
PATCH /users/1
Content-Type: application/merge-patch+json
{
firstName: "Fred"
}
However, I see no easy way for me to know that firstName
is the only property being updated. For example, if I were to make a controller that accepted PATCH
verbs, it could be scaffolded like this:
[Route("users")]
public class UsersController : Controller {
[HttpPatch("{userId:int}")]
public User Patch([FromRoute] int userId, [FromBody] User user) {
// How do I know which properties were set on User at this point?
}
}
public class User {
public String Title { get; set; }
public String FirstName { get; set; }
public String MiddleName { get; set; }
public String LastName { get; set; }
}
But I don't see how I can extract which properties' had keys defined on the JSON object before it was hydrated as a User
and passed to my controller. I cannot assume a value of null
to mean a property was excluded as the caller could be explicitly setting an optional property to null.
Edit
I am aware of the Microsoft.AspNetCore.JsonPatch library. This, unfortunately, expects the caller to use the "[description of changes]" to define a PATCH
as described in RFC 5789, which I find unintuitive and verbose. I am referring to the "JSON Merge Patch" defined in RFC 7396.
A JSON merge patch document describes changes to be made to a target JSON document using a syntax that closely mimics the document being modified.
HTTP POST can support partial updates to a resource. But there is a separate PATCH method. This new HTTP method, PATCH, modifies an existing HTTP resource. The call to the Patch method is sufficient to partially update the corresponding properties of the Employee object in the list.
How it works. A JSON Patch document is just a JSON file containing an array of patch operations. The patch operations supported by JSON Patch are “add”, “remove”, “replace”, “move”, “copy” and “test”. The operations are applied in order: if any of them fail then the whole patch operation should abort.
json-merge is a library allowing you to merge two json files for the JVM written in Kotlin. It currently supports two modes for merging arrays and objects.
for simple types, I found a very simple solution using Newtonsoft.Json merge of JObjects:
public static T Patched<T>(T source, JObject patch) where T : class
{
var sourceObject = JObject.FromObject(source);
sourceObject.Merge(patch, new JsonMergeSettings() {MergeArrayHandling = MergeArrayHandling.Union});
return sourceObject.ToObject<T>();
}
public static T Patched<T>(T source, string patchCode) where T : class
{
return Patched<T>(source, JObject.Parse(patchCode));
}
Hope this helps someone searching for this topic and looking for a simple solution without external packages.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With