Skip to content

Commit e0c68b9

Browse files
authored
Merge pull request #320 from json-api-dotnet/feat/#319
propagate model state errors
2 parents bcd4560 + 63598ab commit e0c68b9

File tree

6 files changed

+53
-13
lines changed

6 files changed

+53
-13
lines changed

src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,15 @@ public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string rel
146146

147147
public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
148148
{
149-
if (_create == null) throw Exceptions.UnSupportedRequestMethod;
149+
if (_create == null)
150+
throw Exceptions.UnSupportedRequestMethod;
150151

151152
if (entity == null)
152153
return UnprocessableEntity();
153154

154155
if (!_jsonApiContext.Options.AllowClientGeneratedIds && !string.IsNullOrEmpty(entity.StringId))
155156
return Forbidden();
157+
156158
if (_jsonApiContext.Options.ValidateModelState && !ModelState.IsValid)
157159
return BadRequest(ModelState.ConvertToErrorCollection());
158160

src/JsonApiDotNetCore/Extensions/ModelStateExtensions.cs

+9-4
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,22 @@ public static class ModelStateExtensions
88
{
99
public static ErrorCollection ConvertToErrorCollection(this ModelStateDictionary modelState)
1010
{
11-
ErrorCollection errors = new ErrorCollection();
11+
ErrorCollection collection = new ErrorCollection();
1212
foreach (var entry in modelState)
1313
{
14-
if (!entry.Value.Errors.Any())
14+
if (entry.Value.Errors.Any() == false)
1515
continue;
16+
1617
foreach (var modelError in entry.Value.Errors)
1718
{
18-
errors.Errors.Add(new Error(400, entry.Key, modelError.ErrorMessage, modelError.Exception != null ? ErrorMeta.FromException(modelError.Exception) : null));
19+
if (modelError.Exception is JsonApiException jex)
20+
collection.Errors.AddRange(jex.GetError().Errors);
21+
else
22+
collection.Errors.Add(new Error(400, entry.Key, modelError.ErrorMessage, modelError.Exception != null ? ErrorMeta.FromException(modelError.Exception) : null));
1923
}
2024
}
21-
return errors;
25+
26+
return collection;
2227
}
2328
}
2429
}

src/JsonApiDotNetCore/Formatters/JsonApiReader.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,9 @@ public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
5252
context.ModelState.AddModelError(context.ModelName, ex, context.Metadata);
5353
return InputFormatterResult.FailureAsync();
5454
}
55-
catch (JsonApiException jex)
55+
catch (JsonApiException)
5656
{
57-
_logger?.LogError(new EventId(), jex, "An error occurred while de-serializing the payload");
58-
context.ModelState.AddModelError(context.ModelName, jex, context.Metadata);
59-
return InputFormatterResult.FailureAsync();
57+
throw;
6058
}
6159
}
6260

src/JsonApiDotNetCore/JsonApiDotNetCore.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<VersionPrefix>2.3.3</VersionPrefix>
3+
<VersionPrefix>2.3.4</VersionPrefix>
44
<TargetFrameworks>$(NetStandardVersion)</TargetFrameworks>
55
<AssemblyName>JsonApiDotNetCore</AssemblyName>
66
<PackageId>JsonApiDotNetCore</PackageId>

src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs

+11-2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public object Deserialize(string requestBody)
5757
var entity = DocumentToObject(document.Data, document.Included);
5858
return entity;
5959
}
60+
catch (JsonApiException)
61+
{
62+
throw;
63+
}
6064
catch (Exception e)
6165
{
6266
throw new JsonApiException(400, "Failed to deserialize request body", e);
@@ -109,10 +113,15 @@ public List<TEntity> DeserializeList<TEntity>(string requestBody)
109113

110114
public object DocumentToObject(DocumentData data, List<DocumentData> included = null)
111115
{
112-
if (data == null) throw new JsonApiException(422, "Failed to deserialize document as json:api.");
116+
if (data == null)
117+
throw new JsonApiException(422, "Failed to deserialize document as json:api.");
113118

114119
var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(data.Type?.ToString());
115-
_jsonApiContext.RequestEntity = contextEntity;
120+
_jsonApiContext.RequestEntity = contextEntity ?? throw new JsonApiException(400,
121+
message: $"This API does not contain a json:api resource named '{data.Type}'.",
122+
detail: "This resource is not registered on the ContextGraph. "
123+
+ "If you are using Entity Framework, make sure the DbSet matches the expected resource name. "
124+
+ "If you have manually registered the resource, check that the call to AddResource correctly sets the public name."); ;
116125

117126
var entity = Activator.CreateInstance(contextEntity.EntityType);
118127

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using JsonApiDotNetCore.Models;
2+
using Xunit;
3+
4+
namespace UnitTests.Models
5+
{
6+
public class IdentifiableTests
7+
{
8+
[Fact]
9+
public void Can_Set_StringId_To_Value_Type()
10+
{
11+
var resource = new IntId();
12+
resource.StringId = "1";
13+
Assert.Equal(1, resource.Id);
14+
}
15+
16+
[Fact]
17+
public void Setting_StringId_To_Null_Sets_Id_As_Default()
18+
{
19+
var resource = new IntId();
20+
resource.StringId = null;
21+
Assert.Equal(0, resource.Id);
22+
}
23+
24+
private class IntId : Identifiable { }
25+
}
26+
}

0 commit comments

Comments
 (0)