Skip to content

Commit d5d5c8d

Browse files
author
Bart Koelman
committed
Unified error messages about the absense of 'type'
1 parent c9a4f5a commit d5d5c8d

22 files changed

+61
-65
lines changed

src/JsonApiDotNetCore/Serialization/RequestAdapters/ResourceIdentityAdapter.cs

+9-13
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,7 @@ protected ResourceIdentityAdapter(IResourceGraph resourceGraph, IResourceFactory
109109

110110
private ResourceContext ConvertType(IResourceIdentity identity, ResourceIdentityRequirements requirements, RequestAdapterState state)
111111
{
112-
if (identity.Type == null)
113-
{
114-
string parent = identity is AtomicReference
115-
? "'ref' element"
116-
:
117-
requirements?.RelationshipName != null &&
118-
state.Request.WriteOperation is WriteOperationKind.CreateResource or WriteOperationKind.UpdateResource
119-
?
120-
$"'{requirements.RelationshipName}' relationship"
121-
: "'data' element";
122-
123-
throw new DeserializationException(state.Position, "Request body must include 'type' element.", $"Expected 'type' element in {parent}.");
124-
}
112+
AssertHasType(identity, state);
125113

126114
using IDisposable _ = state.Position.PushElement("type");
127115

@@ -165,6 +153,14 @@ state.Request.WriteOperation is WriteOperationKind.CreateResource or WriteOperat
165153
return resourceContext;
166154
}
167155

156+
private static void AssertHasType(IResourceIdentity identity, RequestAdapterState state)
157+
{
158+
if (identity.Type == null)
159+
{
160+
throw new ModelConversionException(state.Position, "The 'type' element is required.", null);
161+
}
162+
}
163+
168164
private static void AssertIsKnownResourceType(ResourceContext resourceContext, string typeName, RequestAdapterState state)
169165
{
170166
if (resourceContext == null)

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -598,8 +598,8 @@ public async Task Cannot_create_resource_for_missing_type()
598598

599599
ErrorObject error = responseDocument.Errors[0];
600600
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
601-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
602-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
601+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
602+
error.Detail.Should().BeNull();
603603
error.Source.Pointer.Should().Be("/atomic:operations[0]/data");
604604
}
605605

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ public async Task Cannot_create_for_missing_relationship_type()
232232

233233
ErrorObject error = responseDocument.Errors[0];
234234
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
235-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
236-
error.Detail.Should().Be("Expected 'type' element in 'performers' relationship.");
235+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
236+
error.Detail.Should().BeNull();
237237
error.Source.Pointer.Should().Be("/atomic:operations[0]/data/relationships/performers/data[0]");
238238
}
239239

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ public async Task Cannot_create_for_missing_relationship_type()
297297

298298
ErrorObject error = responseDocument.Errors[0];
299299
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
300-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
301-
error.Detail.Should().Be("Expected 'type' element in 'lyric' relationship.");
300+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
301+
error.Detail.Should().BeNull();
302302
error.Source.Pointer.Should().Be("/atomic:operations[0]/data/relationships/lyric/data");
303303
}
304304

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,8 @@ public async Task Cannot_delete_resource_for_missing_type()
424424

425425
ErrorObject error = responseDocument.Errors[0];
426426
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
427-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
428-
error.Detail.Should().Be("Expected 'type' element in 'ref' element.");
427+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
428+
error.Detail.Should().BeNull();
429429
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
430430
}
431431

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ public async Task Cannot_add_for_missing_type_in_ref()
300300

301301
ErrorObject error = responseDocument.Errors[0];
302302
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
303-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
304-
error.Detail.Should().Be("Expected 'type' element in 'ref' element.");
303+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
304+
error.Detail.Should().BeNull();
305305
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
306306
}
307307

@@ -637,8 +637,8 @@ public async Task Cannot_add_for_missing_type_in_data()
637637

638638
ErrorObject error = responseDocument.Errors[0];
639639
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
640-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
641-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
640+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
641+
error.Detail.Should().BeNull();
642642
error.Source.Pointer.Should().Be("/atomic:operations[0]/data[0]");
643643
}
644644

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ public async Task Cannot_remove_for_missing_type_in_ref()
300300

301301
ErrorObject error = responseDocument.Errors[0];
302302
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
303-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
304-
error.Detail.Should().Be("Expected 'type' element in 'ref' element.");
303+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
304+
error.Detail.Should().BeNull();
305305
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
306306
}
307307

@@ -600,8 +600,8 @@ public async Task Cannot_remove_for_missing_type_in_data()
600600

601601
ErrorObject error = responseDocument.Errors[0];
602602
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
603-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
604-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
603+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
604+
error.Detail.Should().BeNull();
605605
error.Source.Pointer.Should().Be("/atomic:operations[0]/data[0]");
606606
}
607607

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,8 @@ public async Task Cannot_replace_for_missing_type_in_ref()
336336

337337
ErrorObject error = responseDocument.Errors[0];
338338
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
339-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
340-
error.Detail.Should().Be("Expected 'type' element in 'ref' element.");
339+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
340+
error.Detail.Should().BeNull();
341341
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
342342
}
343343

@@ -692,8 +692,8 @@ public async Task Cannot_replace_for_missing_type_in_data()
692692

693693
ErrorObject error = responseDocument.Errors[0];
694694
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
695-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
696-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
695+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
696+
error.Detail.Should().BeNull();
697697
error.Source.Pointer.Should().Be("/atomic:operations[0]/data[0]");
698698
}
699699

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -583,8 +583,8 @@ public async Task Cannot_create_for_missing_type_in_ref()
583583

584584
ErrorObject error = responseDocument.Errors[0];
585585
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
586-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
587-
error.Detail.Should().Be("Expected 'type' element in 'ref' element.");
586+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
587+
error.Detail.Should().BeNull();
588588
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
589589
}
590590

@@ -935,8 +935,8 @@ public async Task Cannot_create_for_missing_type_in_data()
935935

936936
ErrorObject error = responseDocument.Errors[0];
937937
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
938-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
939-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
938+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
939+
error.Detail.Should().BeNull();
940940
error.Source.Pointer.Should().Be("/atomic:operations[0]/data");
941941
}
942942

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,8 @@ public async Task Cannot_replace_for_missing_type_in_relationship_data()
388388

389389
ErrorObject error = responseDocument.Errors[0];
390390
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
391-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
392-
error.Detail.Should().Be("Expected 'type' element in 'tracks' relationship.");
391+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
392+
error.Detail.Should().BeNull();
393393
error.Source.Pointer.Should().Be("/atomic:operations[0]/data/relationships/tracks/data[0]");
394394
}
395395

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -735,8 +735,8 @@ public async Task Cannot_update_resource_for_missing_type_in_ref()
735735

736736
ErrorObject error = responseDocument.Errors[0];
737737
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
738-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
739-
error.Detail.Should().Be("Expected 'type' element in 'ref' element.");
738+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
739+
error.Detail.Should().BeNull();
740740
error.Source.Pointer.Should().Be("/atomic:operations[0]/ref");
741741
}
742742

@@ -905,8 +905,8 @@ public async Task Cannot_update_resource_for_missing_type_in_data()
905905

906906
ErrorObject error = responseDocument.Errors[0];
907907
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
908-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
909-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
908+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
909+
error.Detail.Should().BeNull();
910910
error.Source.Pointer.Should().Be("/atomic:operations[0]/data");
911911
}
912912

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -664,8 +664,8 @@ public async Task Cannot_create_for_missing_type_in_relationship_data()
664664

665665
ErrorObject error = responseDocument.Errors[0];
666666
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
667-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
668-
error.Detail.Should().Be("Expected 'type' element in 'track' relationship.");
667+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
668+
error.Detail.Should().BeNull();
669669
error.Source.Pointer.Should().Be("/atomic:operations[0]/data/relationships/track/data");
670670
}
671671

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,8 @@ public async Task Cannot_create_resource_for_missing_type()
575575

576576
ErrorObject error = responseDocument.Errors[0];
577577
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
578-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
579-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
578+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
579+
error.Detail.Should().BeNull();
580580
error.Source.Pointer.Should().Be("/data");
581581

582582
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,8 @@ public async Task Cannot_create_for_missing_relationship_type()
357357

358358
ErrorObject error = responseDocument.Errors[0];
359359
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
360-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
361-
error.Detail.Should().Be("Expected 'type' element in 'subscribers' relationship.");
360+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
361+
error.Detail.Should().BeNull();
362362
error.Source.Pointer.Should().Be("/data/relationships/subscribers/data[0]");
363363

364364
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToOneRelationshipTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ public async Task Cannot_create_for_missing_relationship_type()
317317

318318
ErrorObject error = responseDocument.Errors[0];
319319
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
320-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
321-
error.Detail.Should().Be("Expected 'type' element in 'assignee' relationship.");
320+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
321+
error.Detail.Should().BeNull();
322322
error.Source.Pointer.Should().Be("/data/relationships/assignee/data");
323323

324324
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

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

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

244244
ErrorObject error = responseDocument.Errors[0];
245245
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
246-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
247-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
246+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
247+
error.Detail.Should().BeNull();
248248
error.Source.Pointer.Should().Be("/data[0]");
249249

250250
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

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

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

360360
ErrorObject error = responseDocument.Errors[0];
361361
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
362-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
363-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
362+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
363+
error.Detail.Should().BeNull();
364364
error.Source.Pointer.Should().Be("/data[0]");
365365

366366
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

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

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

275275
ErrorObject error = responseDocument.Errors[0];
276276
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
277-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
278-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
277+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
278+
error.Detail.Should().BeNull();
279279
error.Source.Pointer.Should().Be("/data[0]");
280280

281281
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

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

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

305305
ErrorObject error = responseDocument.Errors[0];
306306
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
307-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
308-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
307+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
308+
error.Detail.Should().BeNull();
309309
error.Source.Pointer.Should().Be("/data");
310310

311311
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs

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

442442
ErrorObject error = responseDocument.Errors[0];
443443
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
444-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
445-
error.Detail.Should().Be("Expected 'type' element in 'subscribers' relationship.");
444+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
445+
error.Detail.Should().BeNull();
446446
error.Source.Pointer.Should().Be("/data/relationships/subscribers/data[0]");
447447

448448
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs

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

778778
ErrorObject error = responseDocument.Errors[0];
779779
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
780-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
781-
error.Detail.Should().Be("Expected 'type' element in 'data' element.");
780+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
781+
error.Detail.Should().BeNull();
782782
error.Source.Pointer.Should().Be("/data");
783783

784784
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

test/JsonApiDotNetCoreTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateToOneRelationshipTests.cs

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

480480
ErrorObject error = responseDocument.Errors[0];
481481
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
482-
error.Title.Should().Be("Failed to deserialize request body: Request body must include 'type' element.");
483-
error.Detail.Should().Be("Expected 'type' element in 'assignee' relationship.");
482+
error.Title.Should().Be("Failed to deserialize request body: The 'type' element is required.");
483+
error.Detail.Should().BeNull();
484484
error.Source.Pointer.Should().Be("/data/relationships/assignee/data");
485485

486486
responseDocument.Meta["requestBody"].ToString().Should().NotBeNullOrEmpty();

0 commit comments

Comments
 (0)