Skip to content

Commit 9610878

Browse files
fix: 🚑️ error responses for forbidden includes did not include meta information
1 parent ae24c88 commit 9610878

6 files changed

Lines changed: 52 additions & 27 deletions

File tree

‎JsonApiToolkit.Tests/Attributes/AllowedIncludesAttributeTests.cs‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,8 @@ public void OnActionExecuting_MultipleForbidden_ReturnsAllInError()
232232
var objectResult = Assert.IsType<ObjectResult>(context.Result);
233233
var errorResponse = Assert.IsType<JsonApiErrorResponse>(objectResult.Value);
234234

235-
var errorWithMeta = errorResponse.Errors[0] as JsonApiErrorWithMeta;
236-
Assert.NotNull(errorWithMeta);
237-
var meta = errorWithMeta.Meta;
235+
var error = errorResponse.Errors[0];
236+
var meta = error.Meta;
238237
Assert.NotNull(meta);
239238

240239
var forbiddenIncludes = meta["forbiddenIncludes"] as List<string>;
@@ -257,9 +256,8 @@ public void OnActionExecuting_ErrorMetadata_ContainsCorrectInfo()
257256
var objectResult = Assert.IsType<ObjectResult>(context.Result);
258257
var errorResponse = Assert.IsType<JsonApiErrorResponse>(objectResult.Value);
259258

260-
var errorWithMeta = errorResponse.Errors[0] as JsonApiErrorWithMeta;
261-
Assert.NotNull(errorWithMeta);
262-
var meta = errorWithMeta.Meta;
259+
var error = errorResponse.Errors[0];
260+
var meta = error.Meta;
263261
Assert.NotNull(meta);
264262

265263
var requestedIncludes = meta["requestedIncludes"] as List<string>;

‎JsonApiToolkit.Tests/Attributes/AllowedIncludesAttributeWildcardTests.cs‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,9 @@ public void OnActionExecuting_MixedPatterns_ForbidsNonMatching()
132132
Assert.Equal(403, objectResult.StatusCode);
133133

134134
var errorResponse = Assert.IsType<JsonApiErrorResponse>(objectResult.Value);
135-
var errorWithMeta = errorResponse.Errors[0] as JsonApiErrorWithMeta;
136-
Assert.NotNull(errorWithMeta);
135+
var error = errorResponse.Errors[0];
137136

138-
var forbiddenIncludes = errorWithMeta.Meta?["forbiddenIncludes"] as List<string>;
137+
var forbiddenIncludes = error.Meta?["forbiddenIncludes"] as List<string>;
139138
Assert.NotNull(forbiddenIncludes);
140139
Assert.Single(forbiddenIncludes);
141140
Assert.Contains("tags", forbiddenIncludes);

‎JsonApiToolkit.Tests/Integration/AllowedIncludesIntegrationTests.cs‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,38 @@ public async Task GetWithEmptyAttribute_ForbidsAllIncludesAsync()
111111
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
112112
}
113113

114+
[Fact]
115+
public async Task ForbiddenInclude_ContainsMetaInformationAsync()
116+
{
117+
var response = await _client.GetAsync("/api/test/with-allowed?include=forbidden,author");
118+
119+
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
120+
121+
var content = await response.Content.ReadAsStringAsync();
122+
123+
// Verify meta information is present
124+
Assert.Contains("\"meta\":", content);
125+
Assert.Contains("requestedIncludes", content);
126+
Assert.Contains("forbiddenIncludes", content);
127+
Assert.Contains("allowedIncludes", content);
128+
Assert.Contains("forbidden", content);
129+
Assert.Contains("author", content);
130+
}
131+
132+
[Fact]
133+
public async Task EmptyAllowedIncludes_ShowsCorrectErrorDetailAsync()
134+
{
135+
var response = await _client.GetAsync("/api/test/with-empty?include=something");
136+
137+
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
138+
139+
var content = await response.Content.ReadAsStringAsync();
140+
141+
// Error should mention the actual requested include, not empty string
142+
Assert.Contains("something", content);
143+
Assert.DoesNotContain("''", content);
144+
}
145+
114146
public void Dispose()
115147
{
116148
_client?.Dispose();

‎JsonApiToolkit/Attributes/AllowedIncludesAttribute.cs‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ public override void OnActionExecuting(ActionExecutingContext context)
7272
// Empty array means no includes allowed
7373
if (_allowedIncludes.Length == 0)
7474
{
75-
ThrowForbiddenException(queryParams.Include, [], _allowedIncludes, context);
75+
ThrowForbiddenException(
76+
queryParams.Include,
77+
queryParams.Include,
78+
_allowedIncludes,
79+
context
80+
);
7681
return;
7782
}
7883

@@ -120,7 +125,7 @@ ActionExecutingContext context
120125
? $"The requested include '{forbiddenIncludes[0]}' is not allowed for this endpoint"
121126
: $"The requested includes '{string.Join(", ", forbiddenIncludes)}' are not allowed for this endpoint";
122127

123-
var error = new JsonApiErrorWithMeta
128+
var error = new JsonApiError
124129
{
125130
Status = "403",
126131
Title = "Forbidden Include",

‎JsonApiToolkit/Models/Errors/JsonApiError.cs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,11 @@ public class JsonApiError
7777
[JsonPropertyName("source")]
7878
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
7979
public ErrorSource? Source { get; set; }
80+
81+
/// <summary>
82+
/// A meta object containing non-standard meta-information about the error.
83+
/// </summary>
84+
[JsonPropertyName("meta")]
85+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
86+
public Dictionary<string, object>? Meta { get; set; }
8087
}

‎JsonApiToolkit/Models/Errors/JsonApiErrorWithMeta.cs‎

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)