Skip to content

Commit c6e1d25

Browse files
committed
Allow empty include query string parameter value
1 parent 62438bf commit c6e1d25

File tree

5 files changed

+37
-7
lines changed

5 files changed

+37
-7
lines changed

src/JsonApiDotNetCore/Queries/Internal/Parsing/IncludeParser.cs

+10-4
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,18 @@ public IncludeExpression Parse(string source, ResourceType resourceTypeInScope,
3030
protected IncludeExpression ParseInclude(ResourceType resourceTypeInScope, int? maximumDepth)
3131
{
3232
var treeRoot = IncludeTreeNode.CreateRoot(resourceTypeInScope);
33-
34-
ParseRelationshipChain(treeRoot);
33+
bool isAtStart = true;
3534

3635
while (TokenStack.Any())
3736
{
38-
EatSingleCharacterToken(TokenKind.Comma);
37+
if (!isAtStart)
38+
{
39+
EatSingleCharacterToken(TokenKind.Comma);
40+
}
41+
else
42+
{
43+
isAtStart = false;
44+
}
3945

4046
ParseRelationshipChain(treeRoot);
4147
}
@@ -244,7 +250,7 @@ public IncludeExpression ToExpression()
244250

245251
if (element.Relationship is HiddenRootRelationshipAttribute)
246252
{
247-
return new IncludeExpression(element.Children);
253+
return element.Children.Any() ? new IncludeExpression(element.Children) : IncludeExpression.Empty;
248254
}
249255

250256
return new IncludeExpression(ImmutableHashSet.Create(element));

src/JsonApiDotNetCore/QueryStrings/Internal/IncludeQueryStringParameterReader.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class IncludeQueryStringParameterReader : QueryStringParameterReader, IIn
1818

1919
private IncludeExpression? _includeExpression;
2020

21-
public bool AllowEmptyValue => false;
21+
public bool AllowEmptyValue => true;
2222

2323
public IncludeQueryStringParameterReader(IJsonApiRequest request, IResourceGraph resourceGraph, IJsonApiOptions options)
2424
: base(request, resourceGraph)

test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/Includes/IncludeTests.cs

+25
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,31 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
828828
responseDocument.Included[0].Attributes.ShouldContainKey("userName").With(value => value.Should().Be(account.UserName));
829829
}
830830

831+
[Fact]
832+
public async Task Can_select_empty_includes()
833+
{
834+
// Arrange
835+
WebAccount account = _fakers.WebAccount.Generate();
836+
837+
await _testContext.RunOnDatabaseAsync(async dbContext =>
838+
{
839+
dbContext.Accounts.Add(account);
840+
await dbContext.SaveChangesAsync();
841+
});
842+
843+
string route = $"/webAccounts/{account.StringId}?include=";
844+
845+
// Act
846+
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync<Document>(route);
847+
848+
// Assert
849+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK);
850+
851+
responseDocument.Data.SingleValue.ShouldNotBeNull();
852+
853+
responseDocument.Included.Should().BeEmpty();
854+
}
855+
831856
[Fact]
832857
public async Task Cannot_include_unknown_relationship()
833858
{

test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/QueryStringTests.cs

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ public async Task Can_use_unknown_query_string_parameter()
6464
}
6565

6666
[Theory]
67-
[InlineData("include")]
6867
[InlineData("filter")]
6968
[InlineData("sort")]
7069
[InlineData("page[size]")]

test/JsonApiDotNetCoreTests/UnitTests/QueryStringParameters/IncludeParseTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public void Reader_Is_Enabled(JsonApiQueryStringParameters parametersDisabled, b
5050
}
5151

5252
[Theory]
53-
[InlineData("includes", "", "Relationship name expected.")]
5453
[InlineData("includes", " ", "Unexpected whitespace.")]
5554
[InlineData("includes", ",", "Relationship name expected.")]
5655
[InlineData("includes", "posts,", "Relationship name expected.")]
@@ -85,6 +84,7 @@ public void Reader_Read_Fails(string parameterName, string parameterValue, strin
8584
}
8685

8786
[Theory]
87+
[InlineData("includes", "", "")]
8888
[InlineData("includes", "owner", "owner")]
8989
[InlineData("includes", "posts", "posts")]
9090
[InlineData("includes", "owner.posts", "owner.posts")]

0 commit comments

Comments
 (0)