Reputation: 6531
I've written a test using Test Server in dot net core 3.1 and I'm trying to do a PATCH request to an endpoint. However as I'm new to using PATCH, I'm a bit stuck with how to send the correct object that the endpoint is expecting.
[Fact]
public async Task Patch()
{
var operations = new List<Operation>
{
new Operation("replace", "entryId", "'attendance ui", 5)
};
var jsonPatchDocument = new JsonPatchDocument(operations, new DefaultContractResolver());
// Act
var content = new StringContent(JsonConvert.SerializeObject(jsonPatchDocument), Encoding.UTF8, "application/json");
var httpResponse = await HttpClient.PatchAsync($"v1/Entry/1", content);
var actual = await httpResponse.Content.ReadAsStringAsync();
}
[HttpPatch("{entryId}")]
public async Task<ActionResult> Patch(int entryId, [FromBody] JsonPatchDocument<EntryModel> patchDocument)
{
if (patchDocument == null)
{
return BadRequest();
}
var existingEntry = _mapper.Map<EntryModel>(await _entryService.Get(entryId));
patchDocument.ApplyTo(existingEntry);
var entry = _mapper.Map<Entry>(existingEntry);
var updatedEntry = _mapper.Map<Entry>(await _entryService.Update(entryId, entry));
return Ok(await updatedEntry.ModelToPayload());
}
From the example I'm creating a JsonPatchDocument with a list of operations, serializing it to JSON and then doing PatchAsync with HTTP Client with the URL for the endpoint.
So my question is what is the shape of the object that I should be Patching and I'm doing this correctly in general?
I tried sending the EntryModel as shown in the picture below, however patchDocument.Operations has an empty list.
Thanks, Nick
Upvotes: 5
Views: 14179
Reputation: 11
The JsonPatchDocument will not work. To make it work you have to add a media type formater.
Install Microsoft.AspNetCore.Mvc.NewtonsoftJson
In startup.cs , after AddControllers() add ->
.AddNewtonsoftJson(x => x.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); })
If you need to have JSON as the default media type formatter. Keep it before any other media type of formatter.
Upvotes: 0
Reputation: 6531
I ended up solving my problem by doing several things:
services.AddControllers().AddNewtonsoftJson();
in Startup.cs. This is from the Nuget package `Microsoft.AspNetCore.Mvc.Newtonsoft.json. var patchDoc = new JsonPatchDocument<EntryModel>().Replace(o => o.EntryTypeId, 5);
var content = new StringContent(JsonConvert.SerializeObject(patchDoc), Encoding.UTF8, "application/json-patch+json");
Here is the complete code:
/// <summary>
/// Verify PUT /Entrys is working and returns updated records
/// </summary>
[Fact]
public async Task Patch()
{
var patchDoc = new JsonPatchDocument<EntryModel>()
.Replace(o => o.EntryTypeId, 5);
var content = new StringContent(JsonConvert.SerializeObject(patchDoc), Encoding.UTF8, "application/json-patch+json");
var httpResponse = await HttpClient.PatchAsync($"v1/Entry/1", content);
var actual = await httpResponse.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);
Assert.True(httpResponse.IsSuccessStatusCode);
}
/// <summary>
/// Endpoint to do partial update
/// </summary>
/// <returns></returns>
[HttpPatch("{entryId}")]
public async Task<ActionResult> Patch(int entryId, [FromBody] JsonPatchDocument<EntryModel> patchDocument)
{
if (patchDocument == null)
{
return BadRequest();
}
var existingEntry = _mapper.Map<EntryModel>(await _entryService.Get(entryId));
// Apply changes
patchDocument.ApplyTo(existingEntry);
var entry = _mapper.Map<Entry>(existingEntry);
var updatedEntry = _mapper.Map<Entry>(await _entryService.Update(entryId, entry));
return Ok();
}
Upvotes: 4
Reputation: 11919
Take a look at this page: https://learn.microsoft.com/en-us/aspnet/core/web-api/jsonpatch?view=aspnetcore-3.1
But the content is something like:
[ {
"op": "add",
"path": "/customerName",
"value": "Barry" }, {
"op": "add",
"path": "/orders/-",
"value": {
"orderName": "Order2",
"orderType": null
} } ]
Upvotes: 0