diff --git a/src/JsonApiDotNetCore/Serialization/Building/LinkBuilder.cs b/src/JsonApiDotNetCore/Serialization/Building/LinkBuilder.cs index 02321695b8..802bfe0fc1 100644 --- a/src/JsonApiDotNetCore/Serialization/Building/LinkBuilder.cs +++ b/src/JsonApiDotNetCore/Serialization/Building/LinkBuilder.cs @@ -117,8 +117,23 @@ private string GetPageLink(ResourceContext resourceContext, int pageOffset, Page { string queryString = BuildQueryString(parameters => { - parameters["page[size]"] = pageSize.ToString(); - parameters["page[number]"] = pageOffset.ToString(); + if (pageSize == null || pageSize.Equals(_options.DefaultPageSize)) + { + parameters.Remove("page[size]"); + } + else + { + parameters["page[size]"] = pageSize.ToString(); + } + + if (pageOffset == 1) + { + parameters.Remove("page[number]"); + } + else + { + parameters["page[number]"] = pageOffset.ToString(); + } }); return $"{_request.BasePath}/{resourceContext.PublicName}" + queryString; diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PaginationLinkTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PaginationLinkTests.cs index a1e38ad007..728fd699b0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PaginationLinkTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/PaginationLinkTests.cs @@ -56,7 +56,7 @@ public async Task When_page_number_is_specified_it_must_display_correct_top_leve "&fields[owner]=firstName&include=owner&sort=ordinal&foo=bar,baz"; string route = pageNumber != 1 ? routePrefix + $"&page[size]={_defaultPageSize}&page[number]={pageNumber}" - : routePrefix; + : routePrefix + $"&page[size]={_defaultPageSize}"; // Act var response = await _client.GetAsync(route); @@ -67,12 +67,12 @@ public async Task When_page_number_is_specified_it_must_display_correct_top_leve var body = await response.Content.ReadAsStringAsync(); var links = JsonConvert.DeserializeObject(body).Links; - Assert.EndsWith($"{routePrefix}&page[size]={_defaultPageSize}&page[number]={selfLink}", links.Self); + Assert.EndsWith($"{routePrefix}{GetPageNumberInQueryString(selfLink)}", links.Self); if (firstLink.HasValue) { - Assert.EndsWith($"{routePrefix}&page[size]={_defaultPageSize}&page[number]={firstLink.Value}", - links.First); + var expected = $"{routePrefix}{GetPageNumberInQueryString(firstLink.Value)}"; + Assert.EndsWith(expected, links.First); } else { @@ -81,7 +81,8 @@ public async Task When_page_number_is_specified_it_must_display_correct_top_leve if (prevLink.HasValue) { - Assert.EndsWith($"{routePrefix}&page[size]={_defaultPageSize}&page[number]={prevLink}", links.Prev); + var expected = $"{routePrefix}{GetPageNumberInQueryString(prevLink.Value)}"; + Assert.EndsWith(expected, links.Prev); } else { @@ -90,7 +91,8 @@ public async Task When_page_number_is_specified_it_must_display_correct_top_leve if (nextLink.HasValue) { - Assert.EndsWith($"{routePrefix}&page[size]={_defaultPageSize}&page[number]={nextLink}", links.Next); + var expected = $"{routePrefix}{GetPageNumberInQueryString(nextLink.Value)}"; + Assert.EndsWith(expected, links.Next); } else { @@ -99,12 +101,18 @@ public async Task When_page_number_is_specified_it_must_display_correct_top_leve if (lastLink.HasValue) { - Assert.EndsWith($"{routePrefix}&page[size]={_defaultPageSize}&page[number]={lastLink}", links.Last); + var expected = $"{routePrefix}{GetPageNumberInQueryString(lastLink.Value)}"; + Assert.EndsWith(expected, links.Last); } else { Assert.Null(links.Last); } } + + private static string GetPageNumberInQueryString(int offset) + { + return offset == 1 ? string.Empty : $"&page[number]={offset}"; + } } } diff --git a/test/UnitTests/Builders/LinkBuilderTests.cs b/test/UnitTests/Builders/LinkBuilderTests.cs index 8396a5c595..5a5857066b 100644 --- a/test/UnitTests/Builders/LinkBuilderTests.cs +++ b/test/UnitTests/Builders/LinkBuilderTests.cs @@ -14,7 +14,7 @@ namespace UnitTests { public sealed class LinkBuilderTests { - private readonly IPaginationContext _paginationContext; + private readonly IPaginationContext _paginationContext = GetPaginationContext(); private readonly Mock _provider = new Mock(); private readonly IRequestQueryStringAccessor _queryStringAccessor = new FakeRequestQueryStringAccessor("?foo=bar"); private const string _host = "http://www.example.com"; @@ -27,11 +27,6 @@ public sealed class LinkBuilderTests private const string _relSelf = "http://www.example.com/articles/123/relationships/author"; private const string _relRelated = "http://www.example.com/articles/123/author"; - public LinkBuilderTests() - { - _paginationContext = GetPaginationContext(); - } - [Theory] [InlineData(LinkTypes.All, LinkTypes.NotConfigured, _resourceSelf)] [InlineData(LinkTypes.Self, LinkTypes.NotConfigured, _resourceSelf)] @@ -167,8 +162,8 @@ public void BuildTopLevelLinks_GlobalAndResourceConfiguration_ExpectedLinks( if (pages) { Assert.Equal($"{_host}/articles?foo=bar&page[size]=10&page[number]=2", links.Self); - Assert.Equal($"{_host}/articles?foo=bar&page[size]=10&page[number]=1", links.First); - Assert.Equal($"{_host}/articles?foo=bar&page[size]=10&page[number]=1", links.Prev); + Assert.Equal($"{_host}/articles?foo=bar&page[size]=10", links.First); + Assert.Equal($"{_host}/articles?foo=bar&page[size]=10", links.Prev); Assert.Equal($"{_host}/articles?foo=bar&page[size]=10&page[number]=3", links.Next); Assert.Equal($"{_host}/articles?foo=bar&page[size]=10&page[number]=3", links.Last); } @@ -203,7 +198,7 @@ private IJsonApiOptions GetConfiguration(LinkTypes resourceLinks = LinkTypes.All return config.Object; } - private IPaginationContext GetPaginationContext() + private static IPaginationContext GetPaginationContext() { var mock = new Mock(); mock.Setup(x => x.PageNumber).Returns(new PageNumber(2));