diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs index 309705e03d..768e6a4fe6 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.IO; +using System.Net; using System.Threading.Tasks; using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; @@ -25,7 +26,7 @@ public JsonApiReader(IJsonApiDeserializer deserializer, _logger.LogTrace("Executing constructor."); } - public async Task ReadAsync(InputFormatterContext context) + public async Task ReadAsync(InputFormatterContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -36,39 +37,34 @@ public async Task ReadAsync(InputFormatterContext context return await InputFormatterResult.SuccessAsync(null); } + var body = await GetRequestBody(context.HttpContext.Request.Body); + + object model; try { - var body = await GetRequestBody(context.HttpContext.Request.Body); - object model = _deserializer.Deserialize(body); - if (model == null) - { - _logger.LogError("An error occurred while de-serializing the payload"); - } - if (context.HttpContext.Request.Method == "PATCH") - { - bool idMissing; - if (model is IList list) - { - idMissing = CheckForId(list); - } - else - { - idMissing = CheckForId(model); - } - if (idMissing) - { - _logger.LogError("Payload must include id attribute"); - throw new JsonApiException(400, "Payload must include id attribute"); - } - } - return await InputFormatterResult.SuccessAsync(model); + model = _deserializer.Deserialize(body); + } + catch (Exception exception) + { + throw CreateErrorForUnprocessableEntity("An error occurred while de-serializing the payload.", exception); } - catch (Exception ex) + + if (context.HttpContext.Request.Method == "PATCH") { - _logger.LogError(new EventId(), ex, "An error occurred while de-serializing the payload"); - context.ModelState.AddModelError(context.ModelName, ex, context.Metadata); - return await InputFormatterResult.FailureAsync(); + var hasMissingId = model is IList list ? CheckForId(list) : CheckForId(model); + if (hasMissingId) + { + throw CreateErrorForUnprocessableEntity("Payload must include id attribute.", null); + } } + + return await InputFormatterResult.SuccessAsync(model); + } + + private Exception CreateErrorForUnprocessableEntity(string title, Exception exception) + { + _logger.LogInformation(new EventId(), exception, title); + return new JsonApiException(422, title, exception?.Message, null); } /// Checks if the deserialized payload has an ID included diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs index bbe645d17c..486012c78f 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/UpdatingDataTests.cs @@ -5,6 +5,7 @@ using System.Net.Http.Headers; using System.Threading.Tasks; using Bogus; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Data; @@ -78,7 +79,16 @@ public async Task Response400IfUpdatingNotSettableAttribute() var response = await client.SendAsync(request); // Assert - Assert.Equal(422, Convert.ToInt32(response.StatusCode)); + Assert.Equal(HttpStatusCode.UnprocessableEntity, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + var document = JsonConvert.DeserializeObject(body); + Assert.Single(document.Errors); + + var error = document.Errors.Single(); + Assert.Equal(422, error.StatusCode); + Assert.Equal("An error occurred while de-serializing the payload.", error.Title); + Assert.Equal("Property set method not found.", error.Detail); } [Fact] @@ -126,8 +136,16 @@ public async Task Respond_422_If_IdNotInAttributeList() var response = await client.SendAsync(request); // Assert - Assert.Equal(422, Convert.ToInt32(response.StatusCode)); + Assert.Equal(HttpStatusCode.UnprocessableEntity, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + var document = JsonConvert.DeserializeObject(body); + Assert.Single(document.Errors); + var error = document.Errors.Single(); + Assert.Equal(422, error.StatusCode); + Assert.Equal("Payload must include id attribute.", error.Title); + Assert.Null(error.Detail); } [Fact]