Skip to content

Commit c3d1f7f

Browse files
committed
Return Forbidden when operation is inaccessible, to match resource endpoint status code
1 parent 4e0f2a7 commit c3d1f7f

File tree

3 files changed

+19
-19
lines changed

3 files changed

+19
-19
lines changed

Diff for: src/JsonApiDotNetCore/Controllers/BaseJsonApiOperationsController.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ protected virtual void ValidateEnabledOperations(IList<OperationContainer> opera
140140
{
141141
string operationCode = GetOperationCodeText(operationKind);
142142

143-
errors.Add(new ErrorObject(HttpStatusCode.UnprocessableEntity)
143+
errors.Add(new ErrorObject(HttpStatusCode.Forbidden)
144144
{
145145
Title = "The requested operation is not accessible.",
146146
Detail = $"The '{operationCode}' relationship operation is not accessible for relationship '{operationRequest.Relationship}' " +
@@ -155,7 +155,7 @@ protected virtual void ValidateEnabledOperations(IList<OperationContainer> opera
155155
{
156156
string operationCode = GetOperationCodeText(operationKind);
157157

158-
errors.Add(new ErrorObject(HttpStatusCode.UnprocessableEntity)
158+
errors.Add(new ErrorObject(HttpStatusCode.Forbidden)
159159
{
160160
Title = "The requested operation is not accessible.",
161161
Detail = $"The '{operationCode}' resource operation is not accessible for resource type '{operationRequest.PrimaryResourceType}'.",

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Controllers/AtomicCustomConstrainedOperationsControllerTests.cs

+9-9
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public async Task Can_create_resources_for_matching_resource_type()
6969
}
7070

7171
[Fact]
72-
public async Task Cannot_create_resource_for_mismatching_resource_type()
72+
public async Task Cannot_create_resource_for_inaccessible_operation()
7373
{
7474
// Arrange
7575
var requestBody = new
@@ -96,20 +96,20 @@ public async Task Cannot_create_resource_for_mismatching_resource_type()
9696
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
9797

9898
// Assert
99-
httpResponse.ShouldHaveStatusCode(HttpStatusCode.UnprocessableEntity);
99+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.Forbidden);
100100

101101
responseDocument.Errors.ShouldHaveCount(1);
102102

103103
ErrorObject error = responseDocument.Errors[0];
104-
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
104+
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
105105
error.Title.Should().Be("The requested operation is not accessible.");
106106
error.Detail.Should().Be("The 'add' resource operation is not accessible for resource type 'performers'.");
107107
error.Source.ShouldNotBeNull();
108108
error.Source.Pointer.Should().Be("/atomic:operations[0]");
109109
}
110110

111111
[Fact]
112-
public async Task Cannot_update_resource_for_matching_resource_type()
112+
public async Task Cannot_update_resource_for_inaccessible_operation()
113113
{
114114
// Arrange
115115
MusicTrack existingTrack = _fakers.MusicTrack.Generate();
@@ -145,20 +145,20 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
145145
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
146146

147147
// Assert
148-
httpResponse.ShouldHaveStatusCode(HttpStatusCode.UnprocessableEntity);
148+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.Forbidden);
149149

150150
responseDocument.Errors.ShouldHaveCount(1);
151151

152152
ErrorObject error = responseDocument.Errors[0];
153-
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
153+
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
154154
error.Title.Should().Be("The requested operation is not accessible.");
155155
error.Detail.Should().Be("The 'update' resource operation is not accessible for resource type 'musicTracks'.");
156156
error.Source.ShouldNotBeNull();
157157
error.Source.Pointer.Should().Be("/atomic:operations[0]");
158158
}
159159

160160
[Fact]
161-
public async Task Cannot_add_to_ToMany_relationship_for_matching_resource_type()
161+
public async Task Cannot_add_to_ToMany_relationship_for_inaccessible_operation()
162162
{
163163
// Arrange
164164
MusicTrack existingTrack = _fakers.MusicTrack.Generate();
@@ -201,12 +201,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
201201
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
202202

203203
// Assert
204-
httpResponse.ShouldHaveStatusCode(HttpStatusCode.UnprocessableEntity);
204+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.Forbidden);
205205

206206
responseDocument.Errors.ShouldHaveCount(1);
207207

208208
ErrorObject error = responseDocument.Errors[0];
209-
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
209+
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
210210
error.Title.Should().Be("The requested operation is not accessible.");
211211
error.Detail.Should().Be("The 'add' relationship operation is not accessible for relationship 'performers' on resource type 'musicTracks'.");
212212
error.Source.ShouldNotBeNull();

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/AtomicOperations/Controllers/AtomicDefaultConstrainedOperationsControllerTests.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public AtomicDefaultConstrainedOperationsControllerTests(IntegrationTestContext<
2020
}
2121

2222
[Fact]
23-
public async Task Cannot_delete_resource_for_disabled_resource_endpoint()
23+
public async Task Cannot_delete_resource_for_inaccessible_operation()
2424
{
2525
// Arrange
2626
TextLanguage existingLanguage = _fakers.TextLanguage.Generate();
@@ -53,20 +53,20 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
5353
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
5454

5555
// Assert
56-
httpResponse.ShouldHaveStatusCode(HttpStatusCode.UnprocessableEntity);
56+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.Forbidden);
5757

5858
responseDocument.Errors.ShouldHaveCount(1);
5959

6060
ErrorObject error = responseDocument.Errors[0];
61-
error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
61+
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
6262
error.Title.Should().Be("The requested operation is not accessible.");
6363
error.Detail.Should().Be("The 'remove' resource operation is not accessible for resource type 'textLanguages'.");
6464
error.Source.ShouldNotBeNull();
6565
error.Source.Pointer.Should().Be("/atomic:operations[0]");
6666
}
6767

6868
[Fact]
69-
public async Task Cannot_change_ToMany_relationship_for_disabled_resource_endpoints()
69+
public async Task Cannot_change_ToMany_relationship_for_inaccessible_operations()
7070
{
7171
// Arrange
7272
TextLanguage existingLanguage = _fakers.TextLanguage.Generate();
@@ -145,26 +145,26 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
145145
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
146146

147147
// Assert
148-
httpResponse.ShouldHaveStatusCode(HttpStatusCode.UnprocessableEntity);
148+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.Forbidden);
149149

150150
responseDocument.Errors.ShouldHaveCount(3);
151151

152152
ErrorObject error1 = responseDocument.Errors[0];
153-
error1.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
153+
error1.StatusCode.Should().Be(HttpStatusCode.Forbidden);
154154
error1.Title.Should().Be("The requested operation is not accessible.");
155155
error1.Detail.Should().Be("The 'update' relationship operation is not accessible for relationship 'lyrics' on resource type 'textLanguages'.");
156156
error1.Source.ShouldNotBeNull();
157157
error1.Source.Pointer.Should().Be("/atomic:operations[0]");
158158

159159
ErrorObject error2 = responseDocument.Errors[1];
160-
error2.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
160+
error2.StatusCode.Should().Be(HttpStatusCode.Forbidden);
161161
error2.Title.Should().Be("The requested operation is not accessible.");
162162
error2.Detail.Should().Be("The 'add' relationship operation is not accessible for relationship 'lyrics' on resource type 'textLanguages'.");
163163
error2.Source.ShouldNotBeNull();
164164
error2.Source.Pointer.Should().Be("/atomic:operations[1]");
165165

166166
ErrorObject error3 = responseDocument.Errors[2];
167-
error3.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
167+
error3.StatusCode.Should().Be(HttpStatusCode.Forbidden);
168168
error3.Title.Should().Be("The requested operation is not accessible.");
169169
error3.Detail.Should().Be("The 'remove' relationship operation is not accessible for relationship 'lyrics' on resource type 'textLanguages'.");
170170
error3.Source.ShouldNotBeNull();

0 commit comments

Comments
 (0)