Skip to content

Commit 4374719

Browse files
spike83csantero
authored andcommitted
Feat: added metadata on pagination responses (JSONAPIdotNET#115)
* Feat: added pagination with metadata - metadata to indicate the count of pages and total count of records - acceptance tests pagination in combination with filters and sorting * moved total-pages and total-count to Entity Framework specific subclass. reduced the number of count calls to save roundtrips * awaits corrected
1 parent 4635c82 commit 4374719

16 files changed

Lines changed: 423 additions & 21 deletions
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"meta": {
3+
"total-pages": 2,
4+
"total-count": 4
5+
},
6+
"data": [
7+
{
8+
"type": "posts",
9+
"id": "203",
10+
"attributes": {
11+
"content": "Post 3 content",
12+
"created": "2015-02-07T11:11:00.0000000+00:00",
13+
"title": "Post 3"
14+
},
15+
"relationships": {
16+
"author": {
17+
"links": {
18+
"self": "https://www.example.com/posts/203/relationships/author",
19+
"related": "https://www.example.com/posts/203/author"
20+
}
21+
},
22+
"comments": {
23+
"links": {
24+
"self": "https://www.example.com/posts/203/relationships/comments",
25+
"related": "https://www.example.com/posts/203/comments"
26+
}
27+
},
28+
"tags": {
29+
"links": {
30+
"self": "https://www.example.com/posts/203/relationships/tags",
31+
"related": "https://www.example.com/posts/203/tags"
32+
}
33+
}
34+
}
35+
},
36+
{
37+
"type": "posts",
38+
"id": "204",
39+
"attributes": {
40+
"content": "Post 4 content",
41+
"created": "2015-02-08T06:59:00.0000000+00:00",
42+
"title": "Post 4"
43+
},
44+
"relationships": {
45+
"author": {
46+
"links": {
47+
"self": "https://www.example.com/posts/204/relationships/author",
48+
"related": "https://www.example.com/posts/204/author"
49+
}
50+
},
51+
"comments": {
52+
"links": {
53+
"self": "https://www.example.com/posts/204/relationships/comments",
54+
"related": "https://www.example.com/posts/204/comments"
55+
}
56+
},
57+
"tags": {
58+
"links": {
59+
"self": "https://www.example.com/posts/204/relationships/tags",
60+
"related": "https://www.example.com/posts/204/tags"
61+
}
62+
}
63+
}
64+
}
65+
]
66+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"meta": {
3+
"total-pages": 2,
4+
"total-count": 3
5+
},
6+
"data": [
7+
{
8+
"type": "users",
9+
"id": "410",
10+
"attributes": {
11+
"first-name": "Sally",
12+
"last-name": "Burns"
13+
},
14+
"relationships": {
15+
"comments": {
16+
"links": {
17+
"self": "https://www.example.com/users/410/relationships/comments",
18+
"related": "https://www.example.com/users/410/comments"
19+
}
20+
},
21+
"posts": {
22+
"links": {
23+
"self": "https://www.example.com/users/410/relationships/posts",
24+
"related": "https://www.example.com/users/410/posts"
25+
}
26+
},
27+
"user-groups": {
28+
"links": {
29+
"self": "https://www.example.com/users/410/relationships/user-groups",
30+
"related": "https://www.example.com/users/410/user-groups"
31+
}
32+
}
33+
}
34+
},
35+
{
36+
"type": "users",
37+
"id": "406",
38+
"attributes": {
39+
"first-name": "Ed",
40+
"last-name": "Burns"
41+
},
42+
"relationships": {
43+
"comments": {
44+
"links": {
45+
"self": "https://www.example.com/users/406/relationships/comments",
46+
"related": "https://www.example.com/users/406/comments"
47+
}
48+
},
49+
"posts": {
50+
"links": {
51+
"self": "https://www.example.com/users/406/relationships/posts",
52+
"related": "https://www.example.com/users/406/posts"
53+
}
54+
},
55+
"user-groups": {
56+
"links": {
57+
"self": "https://www.example.com/users/406/relationships/user-groups",
58+
"related": "https://www.example.com/users/406/user-groups"
59+
}
60+
}
61+
}
62+
}
63+
]
64+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"meta": {
3+
"total-pages": 2,
4+
"total-count": 3
5+
},
6+
"data": [
7+
{
8+
"type": "users",
9+
"id": "409",
10+
"attributes": {
11+
"first-name": "Charlie",
12+
"last-name": "Burns"
13+
},
14+
"relationships": {
15+
"comments": {
16+
"links": {
17+
"self": "https://www.example.com/users/409/relationships/comments",
18+
"related": "https://www.example.com/users/409/comments"
19+
}
20+
},
21+
"posts": {
22+
"links": {
23+
"self": "https://www.example.com/users/409/relationships/posts",
24+
"related": "https://www.example.com/users/409/posts"
25+
}
26+
},
27+
"user-groups": {
28+
"links": {
29+
"self": "https://www.example.com/users/409/relationships/user-groups",
30+
"related": "https://www.example.com/users/409/user-groups"
31+
}
32+
}
33+
}
34+
},
35+
{
36+
"type": "users",
37+
"id": "406",
38+
"attributes": {
39+
"first-name": "Ed",
40+
"last-name": "Burns"
41+
},
42+
"relationships": {
43+
"comments": {
44+
"links": {
45+
"self": "https://www.example.com/users/406/relationships/comments",
46+
"related": "https://www.example.com/users/406/comments"
47+
}
48+
},
49+
"posts": {
50+
"links": {
51+
"self": "https://www.example.com/users/406/relationships/posts",
52+
"related": "https://www.example.com/users/406/posts"
53+
}
54+
},
55+
"user-groups": {
56+
"links": {
57+
"self": "https://www.example.com/users/406/relationships/user-groups",
58+
"related": "https://www.example.com/users/406/user-groups"
59+
}
60+
}
61+
}
62+
}
63+
]
64+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"meta": {
3+
"total-pages": 3,
4+
"total-count": 3
5+
},
6+
"data": [
7+
{
8+
"type": "users",
9+
"id": "409",
10+
"attributes": {
11+
"first-name": "Charlie",
12+
"last-name": "Burns"
13+
},
14+
"relationships": {
15+
"comments": {
16+
"links": {
17+
"self": "https://www.example.com/users/409/relationships/comments",
18+
"related": "https://www.example.com/users/409/comments"
19+
}
20+
},
21+
"posts": {
22+
"links": {
23+
"self": "https://www.example.com/users/409/relationships/posts",
24+
"related": "https://www.example.com/users/409/posts"
25+
}
26+
},
27+
"user-groups": {
28+
"links": {
29+
"self": "https://www.example.com/users/409/relationships/user-groups",
30+
"related": "https://www.example.com/users/409/user-groups"
31+
}
32+
}
33+
}
34+
}
35+
]
36+
}

JSONAPI.AcceptanceTests.EntityFrameworkTestWebApp.Tests/JSONAPI.AcceptanceTests.EntityFrameworkTestWebApp.Tests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
<Compile Include="CreatingResourcesTests.cs" />
107107
<Compile Include="DeletingResourcesTests.cs" />
108108
<Compile Include="ErrorsTests.cs" />
109+
<Compile Include="PaginationTests.cs" />
109110
<Compile Include="FetchingResourcesTests.cs" />
110111
<Compile Include="HeterogeneousTests.cs" />
111112
<Compile Include="MappedTests.cs" />
@@ -275,8 +276,13 @@
275276
<EmbeddedResource Include="Fixtures\FetchingResources\Get_related_to_many_include_response.json" />
276277
<EmbeddedResource Include="Fixtures\CreatingResources\Responses\Post_with_empty_id_and_include_author_Response.json" />
277278
<EmbeddedResource Include="Fixtures\UpdatingResources\Responses\PatchWithAttributeUpdateWithIncludeResponse.json" />
279+
<EmbeddedResource Include="Fixtures\Pagination\GetAllResponsePaged-2-2.json" />
280+
<EmbeddedResource Include="Fixtures\Pagination\GetFilterPaged-2-1.json" />
281+
<EmbeddedResource Include="Fixtures\Pagination\GetFilterPaged-1-2-sorted.json" />
282+
<EmbeddedResource Include="Fixtures\Pagination\GetFilterPaged-1-2-sorted-desc.json" />
278283
<None Include="packages.config" />
279284
</ItemGroup>
285+
<ItemGroup />
280286
<Choose>
281287
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
282288
<ItemGroup>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System.Net;
2+
using System.Threading.Tasks;
3+
using Microsoft.VisualStudio.TestTools.UnitTesting;
4+
5+
namespace JSONAPI.AcceptanceTests.EntityFrameworkTestWebApp.Tests
6+
{
7+
[TestClass]
8+
public class PaginationTests : AcceptanceTestsBase
9+
{
10+
[TestMethod]
11+
[DeploymentItem(@"Data\Comment.csv", @"Data")]
12+
[DeploymentItem(@"Data\Post.csv", @"Data")]
13+
[DeploymentItem(@"Data\PostTagLink.csv", @"Data")]
14+
[DeploymentItem(@"Data\Tag.csv", @"Data")]
15+
[DeploymentItem(@"Data\User.csv", @"Data")]
16+
public async Task GetPage2Post2()
17+
{
18+
using (var effortConnection = GetEffortConnection())
19+
{
20+
var response = await SubmitGet(effortConnection, "posts?page[number]=1&page[size]=2");
21+
22+
await AssertResponseContent(response, @"Fixtures\Pagination\GetAllResponsePaged-2-2.json", HttpStatusCode.OK);
23+
}
24+
}
25+
26+
[TestMethod]
27+
[DeploymentItem(@"Data\Comment.csv", @"Data")]
28+
[DeploymentItem(@"Data\Post.csv", @"Data")]
29+
[DeploymentItem(@"Data\PostTagLink.csv", @"Data")]
30+
[DeploymentItem(@"Data\Tag.csv", @"Data")]
31+
[DeploymentItem(@"Data\User.csv", @"Data")]
32+
public async Task GetWithFilter()
33+
{
34+
using (var effortConnection = GetEffortConnection())
35+
{
36+
var response = await SubmitGet(effortConnection, "users?filter[last-name]=Burns&page[number]=1&page[size]=1");
37+
38+
await AssertResponseContent(response, @"Fixtures\Pagination\GetFilterPaged-2-1.json", HttpStatusCode.OK);
39+
}
40+
}
41+
42+
43+
[TestMethod]
44+
[DeploymentItem(@"Data\Comment.csv", @"Data")]
45+
[DeploymentItem(@"Data\Post.csv", @"Data")]
46+
[DeploymentItem(@"Data\PostTagLink.csv", @"Data")]
47+
[DeploymentItem(@"Data\Tag.csv", @"Data")]
48+
[DeploymentItem(@"Data\User.csv", @"Data")]
49+
public async Task GetWithFilterSortedAscTest()
50+
{
51+
using (var effortConnection = GetEffortConnection())
52+
{
53+
var response = await SubmitGet(effortConnection, "users?filter[last-name]=Burns&page[number]=0&page[size]=2&sort=first-name");
54+
55+
await AssertResponseContent(response, @"Fixtures\Pagination\GetFilterPaged-1-2-sorted.json", HttpStatusCode.OK);
56+
}
57+
}
58+
59+
60+
[TestMethod]
61+
[DeploymentItem(@"Data\Comment.csv", @"Data")]
62+
[DeploymentItem(@"Data\Post.csv", @"Data")]
63+
[DeploymentItem(@"Data\PostTagLink.csv", @"Data")]
64+
[DeploymentItem(@"Data\Tag.csv", @"Data")]
65+
[DeploymentItem(@"Data\User.csv", @"Data")]
66+
public async Task GetWithFilterSortedDescTest()
67+
{
68+
using (var effortConnection = GetEffortConnection())
69+
{
70+
var response = await SubmitGet(effortConnection, "users?filter[last-name]=Burns&page[number]=0&page[size]=2&sort=-first-name");
71+
72+
await AssertResponseContent(response, @"Fixtures\Pagination\GetFilterPaged-1-2-sorted-desc.json", HttpStatusCode.OK);
73+
}
74+
}
75+
76+
}
77+
}

JSONAPI.AcceptanceTests.EntityFrameworkTestWebApp/Startup.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
using JSONAPI.EntityFramework.Configuration;
1515
using Owin;
1616
using System.Collections.Generic;
17+
using JSONAPI.Documents.Builders;
18+
using JSONAPI.EntityFramework.Documents.Builders;
1719

1820
namespace JSONAPI.AcceptanceTests.EntityFrameworkTestWebApp
1921
{
@@ -112,6 +114,8 @@ internal JsonApiHttpAutofacConfigurator BuildAutofacConfigurator(IAppBuilder app
112114
builder.RegisterType<CustomEntityFrameworkResourceObjectMaterializer>()
113115
.As<IEntityFrameworkResourceObjectMaterializer>();
114116
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
117+
builder.RegisterType<EntityFrameworkQueryableResourceCollectionDocumentBuilder>().As<IQueryableResourceCollectionDocumentBuilder>();
118+
115119
});
116120
configurator.OnApplicationLifetimeScopeBegun(applicationLifetimeScope =>
117121
{

0 commit comments

Comments
 (0)