ASP.NET Core MVC API: How to Perform a Partial Update using HTTP PATCH Verb
ASP.NET Core MVC API: How to Perform a Partial Update using HTTP PATCH Verb
25th June 2020
If you are familiar with API integration, you will be familiar with the CRUD methods that tend to associate themselves with each API controller. You will also be familiar with the HTTP verbs that get used for each method.
The Methods and Verbs
However, if you are new to API integration, or just want a recap, here are the methods and verbs that are used within APIs.
Method
HTTP Verb
Read
GET
Create
POST
Full Update
PUT
Partial Update
PATCH
Delete
DELETE
Partial or Full Update?
We are going to concentrate on when you update, should you do a full update or a partial update?
Picture this scenario. You work for a video game shop. The publishers of a game have officially announced the title of a popular game. You load up the video game record onto your system, which includes the title, publisher and release date.
However, you want to do some additional research on the internet to make sure you have correct title for that video game. Meanwhile, a co-worker of yours has a spreadsheet to update the release dates of a certain number of video games. That spreadsheet includes your game! They go ahead and import the spreadsheet. This updates the release date for your game.
You have finally found the official title of the game, and go ahead and make the change. But wait! There is a problem. Because you haven't reloaded the record, the release date displayed is the date before the spreadsheet was imported.
In this scenario, if you do a full update, it will revert the release date back to it's original value and will hold the incorrect release date.
However, you could do a partial update, only updating the fields that have changed. In this instance, because we have only changed the title of the video game, it will only update the title. All other fields will be left alone.
For this demonstration, we have created a VideoGame class. This will hold information, such as Id, Title, Publisher and Release Date.
// VideoGame.cs
public partial class VideoGame
{
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual string Publisher { get; set; }
public virtual DateTime? ReleaseDate { get; set; }
public VideoGame(int id, string title, string publisher, DateTime? releaseDate)
{
Id = id;
Title = title;
Publisher = publisher;
ReleaseDate = releaseDate;
}
}
Afterwards, we create a Video Game controller. When initalised, we create a list of all the video games we want to store:
// VideoGameController.cs
[Route("api/video-game")]
public class VideoGameController : Controller
{
IList<VideoGame> VideoGames { get; set; }
public VideoGameController()
{
VideoGames = new List<VideoGame>();
VideoGames.Add(new VideoGame(1, "Call of Duty: Warzone", "Activision", new System.DateTime(2020, 3, 10)));
VideoGames.Add(new VideoGame(2, "Friday the 13th: The Game", "Gun Media", new System.DateTime(2017, 5, 26)));
VideoGames.Add(new VideoGame(3, "DOOM Eternal", "Bethesda", new System.DateTime(2020, 3, 20)));
}
}
Creating the PATCH method
Now time to go ahead and create the PATCH method. For the PATCH method, we pass in the Id of the record we wish to update. In addition, we pass in an additional parameter of type JsonPatchDocument which includes a generic class. The generic class will be the class looking to update. In this instance, it will be of type "VideoGame". Remember to include the "[FromBody]" attribute before it.
// VideoGameController.cs
public IActionResult Patch(int id, [FromBody] JsonPatchDocument<VideoGame> patchEntity)
Afterwards, we do a look up of the record against the Id and store it in a variable. If the record does not exist, we throw a 404 not found error.
However, if it is found, we apply the changes from our "patch" entity to our record. This means that we only update properties in our record that are contained in our "patch" entity.
// VideoGameController.cs
[HttpPatch("{id:int}")]
public IActionResult Patch(int id, [FromBody] JsonPatchDocument<VideoGame> patchEntity)
{
var entity = VideoGames.FirstOrDefault(videoGame => videoGame.Id == id);
if (entity == null)
{
return NotFound();
}
patchEntity.ApplyTo(entity, ModelState); // Must have Microsoft.AspNetCore.Mvc.NewtonsoftJson installed
return Ok(entity);
}
We then return the record from our method to verify that the properties that we have changes are the only ones that have updated.
Here is our updated VideoGameController class.
// VideoGameController.cs
[Route("api/video-game")]
public class VideoGameController : Controller
{
IList<VideoGame> VideoGames { get; set; }
public VideoGameController()
{
VideoGames = new List<VideoGame>();
VideoGames.Add(new VideoGame(1, "Call of Duty: Warzone", "Activision", new System.DateTime(2020, 3, 10)));
VideoGames.Add(new VideoGame(2, "Friday the 13th: The Game", "Gun Media", new System.DateTime(2017, 5, 26)));
VideoGames.Add(new VideoGame(3, "DOOM Eternal", "Bethesda", new System.DateTime(2020, 3, 20)));
}
[HttpPatch("{id:int}")]
public IActionResult Patch(int id, [FromBody] JsonPatchDocument<VideoGame> patchEntity)
{
var entity = VideoGames.FirstOrDefault(videoGame => videoGame.Id == id);
if (entity == null)
{
return NotFound();
}
patchEntity.ApplyTo(entity, ModelState); // Must have Microsoft.AspNetCore.Mvc.NewtonsoftJson installed
return Ok(entity);
}
}
How to Test the PATCH Method?
To do this, you can use Postman. In this example, we are going to update the title of "Friday the 13th: The Game" to "Friday the 13th". Create a new request with the following properties:
Endpoint: [YOUR_API_HOST]/api/video-game/2
HTTP Verb: PATCH
Content-Type: application/json
We then need to pass in a JSON formatted body, like the following:
The "path" property represents the name of the property. So, "/title" represents the "Title" property in the VideoGame class.
And that's it! The entity returned should have all the information for that particular game, but with only the title updated.
If you wish to update more then one field, you just need to specify an additional line when providing your body. In this instance we are updating the Title and Release Date in one API call:
We have created an ASP.NET Core MVC API application to test our method. Once the application is running, we open up Postman to check that only the properties that we have changed have been updated.
Reduces Risk
Doing a partial update reduces the risk of data being overwritten. It doesn't eliminate it because you could have updated the release date when updating the title. To stop that from happening, you would have to introduce some sort of system where you lock a record. But it certainly shows some of the benefits of doing a partial update and how to integrate it easily into your ASP.NET Core API.
About the author
David Grace
Senior .NET web developer | ASP.NET Core | C# | Software developer