Skip to content

Commit f05b466

Browse files
authoredAug 8, 2018
Merge pull request #371 from rtablada/rt/validations-422
Validations Send source.pointer
2 parents abbaed2 + 7e22eeb commit f05b466

File tree

5 files changed

+398
-359
lines changed

5 files changed

+398
-359
lines changed
 

‎src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace JsonApiDotNetCore.Controllers
1010
{
11-
public class BaseJsonApiController<T>
11+
public class BaseJsonApiController<T>
1212
: BaseJsonApiController<T, int>
1313
where T : class, IIdentifiable<int>
1414
{
@@ -47,7 +47,7 @@ public class BaseJsonApiController<T, TId>
4747
private readonly ICreateService<T, TId> _create;
4848
private readonly IUpdateService<T, TId> _update;
4949
private readonly IUpdateRelationshipService<T, TId> _updateRelationships;
50-
private readonly IDeleteService<T, TId> _delete;
50+
private readonly IDeleteService<T, TId> _delete;
5151
private readonly IJsonApiContext _jsonApiContext;
5252

5353
public BaseJsonApiController(
@@ -156,7 +156,7 @@ public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
156156
return Forbidden();
157157

158158
if (_jsonApiContext.Options.ValidateModelState && !ModelState.IsValid)
159-
return BadRequest(ModelState.ConvertToErrorCollection());
159+
return UnprocessableEntity(ModelState.ConvertToErrorCollection<T>(_jsonApiContext.ContextGraph));
160160

161161
entity = await _create.CreateAsync(entity);
162162

@@ -169,8 +169,9 @@ public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
169169

170170
if (entity == null)
171171
return UnprocessableEntity();
172+
172173
if (_jsonApiContext.Options.ValidateModelState && !ModelState.IsValid)
173-
return BadRequest(ModelState.ConvertToErrorCollection());
174+
return UnprocessableEntity(ModelState.ConvertToErrorCollection<T>(_jsonApiContext.ContextGraph));
174175

175176
var updatedEntity = await _update.UpdateAsync(id, entity);
176177

‎src/JsonApiDotNetCore/Extensions/ModelStateExtensions.cs

+30
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using JsonApiDotNetCore.Internal;
23
using Microsoft.AspNetCore.Mvc.ModelBinding;
34
using Microsoft.EntityFrameworkCore.Internal;
@@ -6,6 +7,7 @@ namespace JsonApiDotNetCore.Extensions
67
{
78
public static class ModelStateExtensions
89
{
10+
[Obsolete("Use Generic Method ConvertToErrorCollection<T>(IContextGraph contextGraph) instead for full validation errors")]
911
public static ErrorCollection ConvertToErrorCollection(this ModelStateDictionary modelState)
1012
{
1113
ErrorCollection collection = new ErrorCollection();
@@ -23,6 +25,34 @@ public static ErrorCollection ConvertToErrorCollection(this ModelStateDictionary
2325
}
2426
}
2527

28+
return collection;
29+
}
30+
public static ErrorCollection ConvertToErrorCollection<T>(this ModelStateDictionary modelState, IContextGraph contextGraph)
31+
{
32+
ErrorCollection collection = new ErrorCollection();
33+
foreach (var entry in modelState)
34+
{
35+
if (entry.Value.Errors.Any() == false)
36+
continue;
37+
38+
var attrName = contextGraph.GetPublicAttributeName<T>(entry.Key);
39+
40+
foreach (var modelError in entry.Value.Errors)
41+
{
42+
if (modelError.Exception is JsonApiException jex)
43+
collection.Errors.AddRange(jex.GetError().Errors);
44+
else
45+
collection.Errors.Add(new Error(
46+
status: 422,
47+
title: entry.Key,
48+
detail: modelError.ErrorMessage,
49+
meta: modelError.Exception != null ? ErrorMeta.FromException(modelError.Exception) : null,
50+
source: attrName == null ? null : new {
51+
pointer = $"/data/attributes/{attrName}"
52+
}));
53+
}
54+
}
55+
2656
return collection;
2757
}
2858
}

‎src/JsonApiDotNetCore/Internal/ContextGraph.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public string GetPublicAttributeName<TParent>(string internalAttributeName)
122122
{
123123
return GetContextEntity(typeof(TParent))
124124
.Attributes
125-
.Single(a => a.InternalAttributeName == internalAttributeName)
125+
.SingleOrDefault(a => a.InternalAttributeName == internalAttributeName)?
126126
.PublicAttributeName;
127127
}
128128
}

‎src/JsonApiDotNetCore/Internal/Error.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ public class Error
99
{
1010
public Error()
1111
{ }
12-
12+
1313
[Obsolete("Use Error constructors with int typed status")]
14-
public Error(string status, string title, ErrorMeta meta = null, string source = null)
14+
public Error(string status, string title, ErrorMeta meta = null, object source = null)
1515
{
1616
Status = status;
1717
Title = title;
1818
Meta = meta;
1919
Source = source;
2020
}
2121

22-
public Error(int status, string title, ErrorMeta meta = null, string source = null)
22+
public Error(int status, string title, ErrorMeta meta = null, object source = null)
2323
{
2424
Status = status.ToString();
2525
Title = title;
@@ -28,7 +28,7 @@ public Error(int status, string title, ErrorMeta meta = null, string source = nu
2828
}
2929

3030
[Obsolete("Use Error constructors with int typed status")]
31-
public Error(string status, string title, string detail, ErrorMeta meta = null, string source = null)
31+
public Error(string status, string title, string detail, ErrorMeta meta = null, object source = null)
3232
{
3333
Status = status;
3434
Title = title;
@@ -37,29 +37,29 @@ public Error(string status, string title, string detail, ErrorMeta meta = null,
3737
Source = source;
3838
}
3939

40-
public Error(int status, string title, string detail, ErrorMeta meta = null, string source = null)
40+
public Error(int status, string title, string detail, ErrorMeta meta = null, object source = null)
4141
{
4242
Status = status.ToString();
4343
Title = title;
4444
Detail = detail;
4545
Meta = meta;
4646
Source = source;
4747
}
48-
48+
4949
[JsonProperty("title")]
5050
public string Title { get; set; }
5151

5252
[JsonProperty("detail")]
5353
public string Detail { get; set; }
54-
54+
5555
[JsonProperty("status")]
5656
public string Status { get; set; }
5757

5858
[JsonIgnore]
5959
public int StatusCode => int.Parse(Status);
6060

6161
[JsonProperty("source")]
62-
public string Source { get; set; }
62+
public object Source { get; set; }
6363

6464
[JsonProperty("meta")]
6565
public ErrorMeta Meta { get; set; }
@@ -73,8 +73,8 @@ public class ErrorMeta
7373
[JsonProperty("stackTrace")]
7474
public string[] StackTrace { get; set; }
7575

76-
public static ErrorMeta FromException(Exception e)
77-
=> new ErrorMeta {
76+
public static ErrorMeta FromException(Exception e)
77+
=> new ErrorMeta {
7878
StackTrace = e.Demystify().ToString().Split(new[] { "\n"}, int.MaxValue, StringSplitOptions.RemoveEmptyEntries)
7979
};
8080
}

‎test/UnitTests/Controllers/BaseJsonApiController_Tests.cs

+352-344
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.