Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f05b466

Browse files
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

Lines changed: 5 additions & 4 deletions
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

Lines changed: 30 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 10 additions & 10 deletions
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
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /