124

Hot Chocolate GraphQL Pagination Using Cursor Technique[.NET 6]

 2 years ago
source link: https://www.learmoreseekmore.com/2022/01/dot6-hotchocolate-graphql-pagination-using-cursor-technique.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
In this article, we are going to understand the Cursor Pagination technique in Hot Chocolate GraphQL.

GraphQL Cursor Paging:

In GraphQL we have cursor-based pagination. The cursors are opaque, either offset or ID-based pagination can be implemented.
In the cursor-base pagination based on request Graphql query response return 'Edges', 'PageInfo'(object).
Edges consist of an array of objects with properties like 'node', 'cursor'. So 'node' property holds single record data into it. 'cursor' is a base64 string that can be either made by the row number or record primary key id value. So each 'edge' contains 'node'(contains single record data) along with 'cursor', so using the 'cursor' value we can query our server to return the records either before or after the 'cursor' value.
PageInfo consist of  'hasNextPage', 'hasPreviousPage', 'startCursor', 'endCursor'.
Sample Query & Response of cursor pagination:

Create A .Net6 Web API Project:

Let's create a .Net6 Web API sample application to accomplish our demo. We can use either Visual Studio 2022 or Visual Studio Code(using .NET CLI commands) to create any.Net6 application. For this demo, I'm using the 'Visual Studio Code'(using the .NET CLI command) editor.
.NET CLI Command:
dotnet new webapi -o Your_Project_Name

Sample Table Data:

Here I will show a Todo table with some data.

Setup EntityFramework Core Database Context:

Let's install the entity framework core NuGet package.
Package Manager:
Install-Package Microsoft.EntityFrameworkCore -Version 6.0.1
.Net CLI:
dotnet add package Microsoft.EntityFrameworkCore --version 6.0.1
Let's install the entity framework core SQL NuGet package.
Package Manager:
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 6.0.1
.Net CLI:
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 6.0.1
Let's create an entity that represents our 'Todo' table like 'Todo.cs'.
Data/Entities/Todo.cs:
  1. namespace Dot6.HotChoco.Graphql.Paging.Demo.Data.Entities;
  2. public class Todo
  3. public int Id { get; set; }
  4. public string ItemName { get; set; }
  5. public bool IsCompleted { get; set; }
Let's implement the Database context by creating an entity like 'MyWorldDbContext.cs'.
Data/MyWorldDbContext.cs:
  1. using Dot6.HotChoco.Graphql.Paging.Demo.Data.Entities;
  2. using Microsoft.EntityFrameworkCore;
  3. namespace Dot6.HotChoco.Graphql.Paging.Demo.Data;
  4. public class MyWorldDbContext : DbContext
  5. public MyWorldDbContext(DbContextOptions<MyWorldDbContext> context) : base(context)
  6. public DbSet<Todo> Todo{get;set;}
  • (Line: 4) To make a plain class as database context, we have to inherit the 'Microsoft.EntityFrameworkCore.DbContext'.
  • (Line: 9) Entities that represent our 'Todo' table will register inside of the database context.
Add the database connection string into the 'appsettings.Development.json'.
appsettings.Development.json:
  1. "ConnectionStrings": {
  2. "MyWorldDbConectiton":"Your_ConnectionString_Value"

Register the database context into the 'Program.cs'.

Program.cs:
  1. builder.Services.AddDbContext<MyWorldDbContext>(options =>
  2. options.UseSqlServer(builder.Configuration.GetConnectionString("MyWorldDbConectiton"));

Install Hot Chocolate NuGet Package:

Let's install the Hot Chocolate NuGet Package.
Package Manager:
Install-Package HotChocolate.AspNetCore -Version 12.5.0
.Net CLI:
dotnet add package HotChocolate.AspNetCore --version 12.5.0

[UsePaging] GraphQL Attribute:

In Hot Chocolate GraphQL implementing cursor, pagination is very simple, by decorating the [UsePaging]  attribute on the resolver method. So it will read all input fields like 'first', 'after', 'last', 'before' implicitly and use them against the return type of 'IQueriable' or 'IEnumerable' result set of the resolver.

Create GraphQL Query Entity:

So let's create GraphQL Query Entity in which we are going to implement our pagination resolver method. So let's create a query entity like 'TodoQuery.cs'
Queries/TodoQuery.cs:
  1. using Dot6.HotChoco.Graphql.Paging.Demo.Data;
  2. using Dot6.HotChoco.Graphql.Paging.Demo.Data.Entities;
  3. namespace Dot6.HotChoco.Graphql.Paging.Demo.Queries;
  4. public class TodoQuery
  5. [UsePaging]
  6. public IQueryable<Todo> GetTodo([Service] MyWorldDbContext myWorldDbContext)
  7. return myWorldDbContext.Todo.OrderBy(_ => _.Id).AsQueryable();
  • (Line: 9) Decorated our resolver method with 'UsePaging' attribute.
  • (Line: 10-13) Paging can be applied for return types like 'IQueryable', 'IEnumerable'. For good performance use the IQuerible return type because the pagination filters will be directly applied to the raw SQL query.

Register GraphQL Service And Endpoint:

Let's register the GraphQL service and endpoint middleware into the 'Program.cs'.
Program.cs:
  1. using Dot6.HotChoco.Graphql.Paging.Demo.Data;
  2. using Dot6.HotChoco.Graphql.Paging.Demo.Queries;
  3. using Microsoft.EntityFrameworkCore;
  4. var builder = WebApplication.CreateBuilder(args);
  5. builder.Services
  6. .AddGraphQLServer()
  7. .AddQueryType<TodoQuery>();
  8. var app = builder.Build();
  9. // code hidden for display purpose
  10. app.MapGraphQL();
  11. app.Run();
  • (Line: 7-9) Register our GraphQL service as well as our Query Entity.
  • (Line: 13) Configured GraphQL endpoint.

Test Pagination Endpoint:

(1)The initial request simply uses the 'first' input filed. So the 'first' value represents how many records to fetch.
Initail GraphQL Query:
  1. query{
  2. todo(first:4) {
  3. edges{
  4. node {
  5. itemName,
  6. isCompleted
  7. cursor
  8. pageInfo {
  9. hasNextPage
  10. hasPreviousPage
  11. startCursor
  12. endCursor
  • (Line: 2) The 'first' input field specifies the number of records from starting. Here we want to fetch the first '4' records.
  • (Line: 4-8) The 'node' we can request properties of our data.
  • (Line: 9) The cursor is a base64 string of either the row number of the record or 'Id' property of the record inside of the node.
(2) Next page request we will use 'first', 'after' fields. So the 'after' field we have to pass the cursor value of a particular record so that server returns the record after the cursor value record up to the records count that is specified in the 'first'.
Next Page request query:
  1. query{
  2. todo(first:2 after: "Mw==") {
  3. edges{
  4. node {
  5. itemName,
  6. isCompleted
  7. cursor
  8. pageInfo {
  9. hasNextPage
  10. hasPreviousPage
  11. startCursor
  12. endCursor
(3) Previous page requests we will use 'last' and 'before' fields. In the 'before' field we pass cursor value which means records before that cursor values needs to be fetched.
Previous Page request query:
  1. query{
  2. todo(last:2, before: "Mw==") {
  3. edges{
  4. node {
  5. itemName,
  6. isCompleted
  7. cursor
  8. pageInfo {
  9. hasNextPage
  10. hasPreviousPage
  11. startCursor
  12. endCursor

Support Me!
Buy Me A Coffee PayPal Me

Wrapping Up:

Hopefully, I think this article delivered some useful information on a basic CRUD operation in Elasticsearch using Kibana. using I love to have your feedback, suggestions, and better techniques in the comment section below.

Follow Me:


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK