In this article, we are going to implement GraphQL CRUD operation in .NET6, Hot Chocolate(V12), SQL Database.GraphQL:
Hot Chocolate GraphQL:
In the 'appsettings.Development.json' file add the connection string.
GraphQL Variable:
GraphQL:
GraphQL is an open-source data query and manipulation and language for APIs. It is a query language for your API and a server-side runtime for executing queries by using a type system you define for your data. GraphQL can be integrated into any framework like .NET, Java, NestJS, etc and it isn't tied to any specific database or storage engine and is backed by your existing code and data.
GraphQL 2 main operations are like:
- Query(fetching data)
- Mutation(data manipulation like save, update, delete)
Hot Chocolate GraphQL:
Hot Chocolate is an open-source GraphQL server that is compliant with the newest GraphQL latest specs. It is the wrapper library of the original .NET GraphQL library. Hot Chocolate takes the complexity away from building a fully-fledged GraphQL server.
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
dotnet new webapi -o Your_Project_Name
Install Entity Framework Core NuGet:
Now install the entity framework core NuGet.
Package Manager Command:
Install-Package Microsoft.EntityFrameworkCore -Version 6.0.1
Install-Package Microsoft.EntityFrameworkCore -Version 6.0.1
.Net CLI Command:
dotnet add package Microsoft.EntityFrameworkCore --version 6.0.1
dotnet add package Microsoft.EntityFrameworkCore --version 6.0.1
Now install SQL library which dependant on entity framework core NuGet.
Package Manager Command:
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 6.0.1
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 6.0.1
.Net CLI Command:
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 6.0.1
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 6.0.1
SQL Query To Create A Sample Table:
Run the below command to the sample table.
CREATE TABLE [dbo].[Cake] ( [Id] INT IDENTITY (1, 1) NOT NULL, [Name] VARCHAR (MAX) NULL, [Price] DECIMAL (18, 2) NULL, [Description] VARCHAR (MAX) NULL );
Setup Entity Framework Core DatabaseContext:
Let's create a class that represents our table. So let's create folders like 'Data' and subfolders like 'Entities' and then add a class like 'Cake.cs'
Data/Entities/Cake.cs:
namespace Dot6.HotChoco12.GraphQL.CRUD.Demo.Data.Entities; public class Cake { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public string Description { get; set; } }To manage or control all the table classes we have to create DatabaseContext class. So let's create our context class like 'MyWorldDbContext.cs' in the 'Data' folder.
Data/MyWorldDbContext.cs:
using Dot6.HotChoco12.GraphQL.CRUD.Demo.Data.Entities; using Microsoft.EntityFrameworkCore; namespace Dot6.HotChoco12.GraphQL.CRUD.Demo.Data; public class MyWorldDbContext : DbContext { public MyWorldDbContext(DbContextOptions<MyWorldDbContext> options) : base(options) { } public DbSet<Cake> Cake { get; set; } }
- (Line: 6) The 'Microsoft.EntityFrameworkCore.DbContext' needs to be inherited by our 'MyWorldDbContext' to act as a Database context class.
- (Line: 8) The 'Microsoft.EntityFrameworkCore.DbContextOptions' is instance of options that we are going to register in 'Program.cs' like 'ConnectionString', 'DatabaseProvider', etc.
- (Line: 12) All our table classes must be registered inside of our Database context class with 'DbSet<T>' so that the entity framework core can communicate with tables of the database.
appsettings.Development.json:
"ConnectionStrings":{ "MyWorldDbConnection":"your_connection" }Register the Database Context service in the 'Program.cs' file for the dependency injection.
builder.Services.AddDbContext<MyWorldDbContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("MyWorldDbConnection")); });
Install Hot Chocolate NuGet:
Let's install the Hot Chocolate NuGet Package.
Package Manager Command:
Install-Package HotChocolate.AspNetCore -Version 12.6.0
Install-Package HotChocolate.AspNetCore -Version 12.6.0
.NET CLI Command:
dotnet add package HotChocolate.AspNetCore --version 12.6.0
dotnet add package HotChocolate.AspNetCore --version 12.6.0
Configure GraphQL Service And Endpoint:
Now let's register the GraphQL service into the 'Program.cs'.
Program.cs:
builder.Services.AddGraphQLServer();Now let's register the GraphQL endpoint into the 'Program.cs'.
Program.cs:
app.MapGraphQL();
Read Operation:
In GraphQL fetching data can be called 'Query'. Let's frame GraphQL 'Query' to read the data from the server.
Let's create 'Query' entity like 'QueryType.cs'. Add resolver method that returns a collection of data. In GraphQL 'Resolver' is a method that contains logic to return the response to the users. So let's create a new folder like 'GqlTypes' inside of it add 'QueryType.cs'.
GqlTypes/QueryType.cs:
using Dot6.HotChoco12.GraphQL.CRUD.Demo.Data; using Dot6.HotChoco12.GraphQL.CRUD.Demo.Data.Entities; using Microsoft.EntityFrameworkCore; namespace Dot6.HotChoco12.GraphQL.CRUD.Demo.GqlTypes; public class QueryType { public async Task<List<Cake>> AllCakesAsync([Service] MyWorldDbContext context) { return await context.Cake.ToListAsync(); } }
- Here QueryType is plain c# class.
- The 'AllCakesAsync' method is 'Resolver'. The GraphQL resolvers are logic units that return responses to the user.
- (Line: 9) Injected our database context into our resolver method as an input parameter. The 'HotChocolate.Service' attribute helps for the context injection at the scope level.
- (Line: 11) Returning collection of results from the database.
Program.cs:
builder.Services .AddGraphQLServer() .AddQueryType<QueryType>();Sample query for fetching the data:
query{ allCakes{ id name } }
- (Line: 1) The 'query' GraphQL keyword to specify this is a read operation.
- (Line: 2) Our c# resolver method name 'AllCakesAsync' so to invoke this resolver method, in GraphQL we have to call 'allCakes'(Lower camel casing, 'async' keyword can be ignored).
- (Line: 3-4) Inside of the resolver method name we have to specify the properties names which we required, the server also returns only the requested properties. The property names also should follow the Lower camel case.
Create Operation:
In GraphQL saving or updating or deleting of data is called 'Mutation'. Let's frame a 'Mutation' to create a new into the database.
Let's create a 'Mutation' entity like 'MutationType.cs'. Add a resolver method that creates a new record into the database. So inside of the 'GqlType' folder let's add a mutation entity like 'MutationType.cs'.
GqlType/MutationType.cs:
using Dot6.HotChoco12.GraphQL.CRUD.Demo.Data; using Dot6.HotChoco12.GraphQL.CRUD.Demo.Data.Entities; namespace Dot6.HotChoco12.GraphQL.CRUD.Demo.GqlTypes; public class MutationType { public async Task<Cake> SaveCakeAsync([Service] MyWorldDbContext context, Cake newCake) { context.Cake.Add(newCake); await context.SaveChangesAsync(); return newCake; } }
- Here 'MutationType' is a plain c# class.
- Here 'SaveCakeAsync()' is a resolver method.
- Here 1st parameter is our Database context, 2nd parameter is our new record that needs to be created.
- (Line: 11-13) Here we are saving the new record into the database and then return the new record as a response.
Program.cs:
builder.Services .AddGraphQLServer() .AddQueryType<QueryType>() .AddMutationType<MutationType>();Sample mutation to insert a new record:-
GraphQL Variable:
{ "newCake": { "id": 0, "description": "Strawberry flavored cake", "name": "Strawberry Cake", "price": 75 } }
- (Line: 2) The 'newCake' GraphQL variable name
- (Line: 3-6) Our payload needs to be saved to the database.
mutation($newCake:CakeInput!){ saveCake(newCake:$newCake) { id } }
- (Line: 1) The 'mutation' is Graphql keyword is specified for updating the data into the server. The '$newCake' is the GraphQL variable we defined above but here we need to append '$'. The 'CakeInput!'(non-nullable type), it is a GraphQL type that was generated based on our payload type at a server. At the server our input payload type is 'Cake', so on the GraphQL side, its type looks like 'CakeInput'(So the convention is like 'Cake'(C# class name) + 'Input').
- (Line: 2) The 'saveCake' is our resolver method name its naming convention is Lower Camel Case.
- The 'nameCake' is a variable name the same as at the sever resolver method input parameter name.
- (Line: 3) Requesting the newly created record id.
Update Operation:
The update operation is a GraphQL mutation. Let's create a new resolver method for updating the record.
GqlType/MutationType.cs:
public async Task<Cake> UpdateCakeAsync([Service] MyWorldDbContext context, Cake updateCake) { context.Cake.Update(updateCake); await context.SaveChangesAsync(); return updateCake; }
- Here is our mutation resolver method for updating the record to the database.
Variable:
{ "updateCake": { "id": 16002, "description": "Strawberry flavored Sugar cake", "name": "Strawberry Cake", "price": 85 } }
- Here 'updateCake' is the name of our GraphQL variable. Here we must have the 'id' value for updating the record.
mutation($updateCake:CakeInput!){ updateCake(updateCake:$updateCake) { id description name price } }
Delete Operation:
The delete operation is GraphQL Mutation. Let's add a new resolver method for deleting the record.
GqlType/MutationType.cs:
public async Task<string> DeleteCakeAsync([Service] MyWorldDbContext context, int id) { var cakeToDelete = await context.Cake.FindAsync(id); if (cakeToDelete == null) { return "Invalid Operation"; } context.Cake.Remove(cakeToDelete); await context.SaveChangesAsync(); return "Record Deleted!"; }
- Here we passing 'id' as input parameter for our resolver method 'DeleteCakeAsync()'.
- (Line: 3) Fetching the record from the database.
- (Line: 4-7) Checking the record to be deleted exist in the database or not.
- (Line: 8-9) Deleting the record from the database.
Variable:
{ "id":16002 }
- Here 'id' GraphQL variable name.
mutation($id:Int!){ deleteCake(id:$id) }
- Here 'Int!' non-nullable Integer of GraphQL type.
Support Me!
Buy Me A Coffee
PayPal Me
Video Session:
Wrapping Up:
Hopefully, I think this article delivered some useful information on a basic CRUD operation in Hot Chocolate(V12) GraphQL in .Net6. using I love to have your feedback, suggestions, and better techniques in the comment section below.
Comments
Post a Comment