Skip to content

Commit 2c60a42

Browse files
author
Bart Koelman
committed
Additional unification of error messages
1 parent 5f618d2 commit 2c60a42

16 files changed

+48
-62
lines changed

src/JsonApiDotNetCore/Serialization/RequestAdapters/AtomicOperationObjectAdapter.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private static void AssertNoHref(AtomicOperationObject atomicOperationObject, Re
6363
{
6464
using (state.Position.PushElement("href"))
6565
{
66-
throw new DeserializationException(state.Position, "Usage of the 'href' element is not supported.", null);
66+
throw new ModelConversionException(state.Position, "The 'href' element is not supported.", null);
6767
}
6868
}
6969
}
@@ -78,7 +78,7 @@ private WriteOperationKind ConvertOperationCode(AtomicOperationObject atomicOper
7878
{
7979
using (state.Position.PushElement("ref"))
8080
{
81-
throw new DeserializationException(state.Position, "The 'ref.relationship' element is required.", null);
81+
throw new ModelConversionException(state.Position, "The 'relationship' element is required.", null);
8282
}
8383
}
8484

@@ -92,7 +92,7 @@ private WriteOperationKind ConvertOperationCode(AtomicOperationObject atomicOper
9292
{
9393
if (atomicOperationObject.Ref == null)
9494
{
95-
throw new DeserializationException(state.Position, "The 'ref' element is required.", null);
95+
throw new ModelConversionException(state.Position, "The 'ref' element is required.", null);
9696
}
9797

9898
return atomicOperationObject.Ref.Relationship != null ? WriteOperationKind.RemoveFromRelationship : WriteOperationKind.DeleteResource;

src/JsonApiDotNetCore/Serialization/RequestAdapters/AtomicReferenceAdapter.cs

-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using JsonApiDotNetCore.Configuration;
3-
using JsonApiDotNetCore.Middleware;
43
using JsonApiDotNetCore.Resources;
54
using JsonApiDotNetCore.Resources.Annotations;
65
using JsonApiDotNetCore.Serialization.Objects;
@@ -44,17 +43,5 @@ private RelationshipAttribute ConvertRelationship(string relationshipName, Resou
4443

4544
return relationship;
4645
}
47-
48-
private static void AssertToManyInAddOrRemoveRelationship(RelationshipAttribute relationship, RequestAdapterState state)
49-
{
50-
bool requireToManyRelationship = state.Request.WriteOperation == WriteOperationKind.AddToRelationship ||
51-
state.Request.WriteOperation == WriteOperationKind.RemoveFromRelationship;
52-
53-
if (requireToManyRelationship && relationship is not HasManyAttribute)
54-
{
55-
throw new DeserializationException(state.Position, "Only to-many relationships can be targeted through this operation.",
56-
$"Relationship '{relationship.PublicName}' must be a to-many relationship.");
57-
}
58-
}
5946
}
6047
}

src/JsonApiDotNetCore/Serialization/RequestAdapters/OperationsDocumentAdapter.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ private static void AssertHasOperations(IEnumerable<AtomicOperationObject> atomi
3838
{
3939
if (atomicOperationObjects.IsNullOrEmpty())
4040
{
41-
throw new DeserializationException(state.Position, "No operations found.", null);
41+
throw new ModelConversionException(state.Position, "No operations found.", null);
4242
}
4343
}
4444

4545
private void AssertMaxOperationsNotExceeded(ICollection<AtomicOperationObject> atomicOperationObjects, RequestAdapterState state)
4646
{
4747
if (atomicOperationObjects.Count > _options.MaximumOperationsPerRequest)
4848
{
49-
throw new DeserializationException(state.Position, "Request exceeds the maximum number of operations.",
50-
$"The number of operations in this request ({atomicOperationObjects.Count}) is higher than {_options.MaximumOperationsPerRequest}.");
49+
throw new ModelConversionException(state.Position, "Too many operations in request.",
50+
$"The number of operations in this request ({atomicOperationObjects.Count}) is higher " +
51+
$"than the maximum of {_options.MaximumOperationsPerRequest}.");
5152
}
5253
}
5354

src/JsonApiDotNetCore/Serialization/RequestAdapters/RelationshipDataAdapter.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ public object Convert(SingleOrManyData<ResourceIdentifierObject> data, Relations
9090
private IIdentifiable ConvertToOneRelationshipData(SingleOrManyData<ResourceIdentifierObject> data, RelationshipAttribute relationship,
9191
ResourceIdentityRequirements requirements, RequestAdapterState state)
9292
{
93-
AssertHasNoManyValue(data, relationship, state);
93+
AssertHasSingleValue(data, relationship, state);
9494

9595
return data.SingleValue != null ? _resourceIdentifierObjectAdapter.Convert(data.SingleValue, requirements, state) : null;
9696
}
9797

98-
private static void AssertHasNoManyValue(SingleOrManyData<ResourceIdentifierObject> data, RelationshipAttribute relationship, RequestAdapterState state)
98+
private static void AssertHasSingleValue(SingleOrManyData<ResourceIdentifierObject> data, RelationshipAttribute relationship, RequestAdapterState state)
9999
{
100-
if (data.ManyValue != null)
100+
if (!data.IsAssigned || data.ManyValue != null)
101101
{
102102
throw new DeserializationException(state.Position, "Expected single data element for to-one relationship.",
103103
$"Expected single data element for '{relationship.PublicName}' relationship.");

src/JsonApiDotNetCore/Serialization/RequestAdapters/ResourceDocumentAdapter.cs

+1-19
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
using System.Collections.Generic;
2-
using System.Net;
32
using JsonApiDotNetCore.Configuration;
4-
using JsonApiDotNetCore.Errors;
53
using JsonApiDotNetCore.Middleware;
64
using JsonApiDotNetCore.Resources;
7-
using JsonApiDotNetCore.Resources.Annotations;
85
using JsonApiDotNetCore.Serialization.Objects;
96

107
namespace JsonApiDotNetCore.Serialization.RequestAdapters
@@ -50,7 +47,7 @@ public object Convert(Document document, RequestAdapterState state)
5047
return new HashSet<IIdentifiable>(IdentifiableComparer.Instance);
5148
}
5249

53-
AssertToManyInAddOrRemoveRelationship(state);
50+
ResourceIdentityAdapter.AssertToManyInAddOrRemoveRelationship(state.Request.Relationship, state);
5451

5552
state.WritableTargetedFields.Relationships.Add(state.Request.Relationship);
5653
return _relationshipDataAdapter.Convert(document.Data, state.Request.Relationship, false, state);
@@ -75,20 +72,5 @@ private ResourceIdentityRequirements CreateIdentityRequirements(RequestAdapterSt
7572

7673
return requirements;
7774
}
78-
79-
private static void AssertToManyInAddOrRemoveRelationship(RequestAdapterState state)
80-
{
81-
bool requireToManyRelationship = state.Request.WriteOperation == WriteOperationKind.AddToRelationship ||
82-
state.Request.WriteOperation == WriteOperationKind.RemoveFromRelationship;
83-
84-
if (requireToManyRelationship && state.Request.Relationship is not HasManyAttribute)
85-
{
86-
throw new JsonApiException(new ErrorObject(HttpStatusCode.Forbidden)
87-
{
88-
Title = "Only to-many relationships can be targeted through this endpoint.",
89-
Detail = $"Relationship '{state.Request.Relationship.PublicName}' must be a to-many relationship."
90-
});
91-
}
92-
}
9375
}
9476
}

src/JsonApiDotNetCore/Serialization/RequestAdapters/ResourceIdentityAdapter.cs

+16
Original file line numberDiff line numberDiff line change
@@ -203,5 +203,21 @@ protected static void AssertIsKnownRelationship(RelationshipAttribute relationsh
203203
$"Relationship '{relationshipName}' does not exist on resource type '{resourceContext.PublicName}'.");
204204
}
205205
}
206+
207+
protected internal static void AssertToManyInAddOrRemoveRelationship(RelationshipAttribute relationship, RequestAdapterState state)
208+
{
209+
bool requireToManyRelationship = state.Request.WriteOperation == WriteOperationKind.AddToRelationship ||
210+
state.Request.WriteOperation == WriteOperationKind.RemoveFromRelationship;
211+
212+
if (requireToManyRelationship && relationship is not HasManyAttribute)
213+
{
214+
string message = state.Request.Kind == EndpointKind.AtomicOperations
215+
? "Only to-many relationships can be targeted through this operation."
216+
: "Only to-many relationships can be targeted through this endpoint.";
217+
218+
throw new ModelConversionException(state.Position, message, $"Relationship '{relationship.PublicName}' is not a to-many relationship.",
219+
HttpStatusCode.Forbidden);
220+
}
221+
}
206222
}
207223
}

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ public async Task Cannot_create_resource_for_href_element()
494494

495495
ErrorObject error = responseDocument.Errors[0];
496496
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
497-
error.Title.Should().Be("Failed to deserialize request body: Usage of the 'href' element is not supported.");
497+
error.Title.Should().Be("Failed to deserialize request body: The 'href' element is not supported.");
498498
error.Detail.Should().BeNull();
499499
error.Source.Pointer.Should().Be("/atomic:operations[0]/href");
500500
}
@@ -530,7 +530,7 @@ public async Task Cannot_create_resource_for_ref_element()
530530

531531
ErrorObject error = responseDocument.Errors[0];
532532
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
533-
error.Title.Should().Be("Failed to deserialize request body: The 'ref.relationship' element is required.");
533+
error.Title.Should().Be("Failed to deserialize request body: The 'relationship' element is required.");
534534
error.Detail.Should().BeNull();
535535
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
536536
}

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ public async Task Cannot_delete_resource_for_href_element()
356356

357357
ErrorObject error = responseDocument.Errors[0];
358358
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
359-
error.Title.Should().Be("Failed to deserialize request body: Usage of the 'href' element is not supported.");
359+
error.Title.Should().Be("Failed to deserialize request body: The 'href' element is not supported.");
360360
error.Detail.Should().BeNull();
361361
error.Source.Pointer.Should().Be("/atomic:operations[0]/href");
362362
}

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Mixed/MaximumOperationsPerRequestTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ public async Task Cannot_process_more_operations_than_maximum()
7272

7373
ErrorObject error = responseDocument.Errors[0];
7474
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
75-
error.Title.Should().Be("Failed to deserialize request body: Request exceeds the maximum number of operations.");
76-
error.Detail.Should().Be("The number of operations in this request (3) is higher than 2.");
75+
error.Title.Should().Be("Failed to deserialize request body: Too many operations in request.");
76+
error.Detail.Should().Be("The number of operations in this request (3) is higher than the maximum of 2.");
7777
error.Source.Pointer.Should().Be("/atomic:operations");
7878
}
7979

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
6464
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
6565

6666
// Assert
67-
httpResponse.Should().HaveStatusCode(HttpStatusCode.UnprocessableEntity);
67+
httpResponse.Should().HaveStatusCode(HttpStatusCode.Forbidden);
6868

6969
responseDocument.Errors.Should().HaveCount(1);
7070

7171
ErrorObject error = responseDocument.Errors[0];
72-
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
72+
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
7373
error.Title.Should().Be("Failed to deserialize request body: Only to-many relationships can be targeted through this operation.");
74-
error.Detail.Should().Be("Relationship 'ownedBy' must be a to-many relationship.");
74+
error.Detail.Should().Be("Relationship 'ownedBy' is not a to-many relationship.");
7575
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref/relationship");
7676
}
7777

@@ -263,7 +263,7 @@ public async Task Cannot_add_for_href_element()
263263

264264
ErrorObject error = responseDocument.Errors[0];
265265
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
266-
error.Title.Should().Be("Failed to deserialize request body: Usage of the 'href' element is not supported.");
266+
error.Title.Should().Be("Failed to deserialize request body: The 'href' element is not supported.");
267267
error.Detail.Should().BeNull();
268268
error.Source.Pointer.Should().Be("/atomic:operations[0]/href");
269269
}
@@ -507,7 +507,7 @@ public async Task Cannot_add_for_missing_relationship_in_ref()
507507

508508
ErrorObject error = responseDocument.Errors[0];
509509
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
510-
error.Title.Should().Be("Failed to deserialize request body: The 'ref.relationship' element is required.");
510+
error.Title.Should().Be("Failed to deserialize request body: The 'relationship' element is required.");
511511
error.Detail.Should().BeNull();
512512
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
513513
}

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
6565
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
6666

6767
// Assert
68-
httpResponse.Should().HaveStatusCode(HttpStatusCode.UnprocessableEntity);
68+
httpResponse.Should().HaveStatusCode(HttpStatusCode.Forbidden);
6969

7070
responseDocument.Errors.Should().HaveCount(1);
7171

7272
ErrorObject error = responseDocument.Errors[0];
73-
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
73+
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
7474
error.Title.Should().Be("Failed to deserialize request body: Only to-many relationships can be targeted through this operation.");
75-
error.Detail.Should().Be("Relationship 'ownedBy' must be a to-many relationship.");
75+
error.Detail.Should().Be("Relationship 'ownedBy' is not a to-many relationship.");
7676
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref/relationship");
7777
}
7878

@@ -263,7 +263,7 @@ public async Task Cannot_remove_for_href_element()
263263

264264
ErrorObject error = responseDocument.Errors[0];
265265
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
266-
error.Title.Should().Be("Failed to deserialize request body: Usage of the 'href' element is not supported.");
266+
error.Title.Should().Be("Failed to deserialize request body: The 'href' element is not supported.");
267267
error.Detail.Should().BeNull();
268268
error.Source.Pointer.Should().Be("/atomic:operations[0]/href");
269269
}

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ public async Task Cannot_replace_for_href_element()
299299

300300
ErrorObject error = responseDocument.Errors[0];
301301
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
302-
error.Title.Should().Be("Failed to deserialize request body: Usage of the 'href' element is not supported.");
302+
error.Title.Should().Be("Failed to deserialize request body: The 'href' element is not supported.");
303303
error.Detail.Should().BeNull();
304304
error.Source.Pointer.Should().Be("/atomic:operations[0]/href");
305305
}

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicUpdateToOneRelationshipTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ public async Task Cannot_create_for_href_element()
546546

547547
ErrorObject error = responseDocument.Errors[0];
548548
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
549-
error.Title.Should().Be("Failed to deserialize request body: Usage of the 'href' element is not supported.");
549+
error.Title.Should().Be("Failed to deserialize request body: The 'href' element is not supported.");
550550
error.Detail.Should().BeNull();
551551
error.Source.Pointer.Should().Be("/atomic:operations[0]/href");
552552
}

test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicUpdateResourceTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ public async Task Cannot_update_resource_for_href_element()
631631

632632
ErrorObject error = responseDocument.Errors[0];
633633
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
634-
error.Title.Should().Be("Failed to deserialize request body: Usage of the 'href' element is not supported.");
634+
error.Title.Should().Be("Failed to deserialize request body: The 'href' element is not supported.");
635635
error.Detail.Should().BeNull();
636636
error.Source.Pointer.Should().Be("/atomic:operations[0]/href");
637637
}

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
5858

5959
ErrorObject error = responseDocument.Errors[0];
6060
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
61-
error.Title.Should().Be("Only to-many relationships can be targeted through this endpoint.");
62-
error.Detail.Should().Be("Relationship 'assignee' must be a to-many relationship.");
61+
error.Title.Should().Be("Failed to deserialize request body: Only to-many relationships can be targeted through this endpoint.");
62+
error.Detail.Should().Be("Relationship 'assignee' is not a to-many relationship.");
6363
error.Source.Should().BeNull();
6464
}
6565

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
7373

7474
ErrorObject error = responseDocument.Errors[0];
7575
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
76-
error.Title.Should().Be("Only to-many relationships can be targeted through this endpoint.");
77-
error.Detail.Should().Be("Relationship 'assignee' must be a to-many relationship.");
76+
error.Title.Should().Be("Failed to deserialize request body: Only to-many relationships can be targeted through this endpoint.");
77+
error.Detail.Should().Be("Relationship 'assignee' is not a to-many relationship.");
7878
error.Source.Should().BeNull();
7979
}
8080

0 commit comments

Comments
 (0)