- Registering the DB Context Service
- Configuring EF Migrations
- Adding GraphQL
- Adding a Query
- Adding a Mutation
- Summary
-
To begin, create a new project for our GraphQL server:
dotnet new sln --name ConferencePlanner
dotnet new web --name GraphQL
dotnet sln add GraphQL
-
Update the
launchSettings.json
file in theProperties
directory as follows:- Remove the
iisSettings
and theIIS Express
profile. - Change
launchBrowser
tofalse
in thehttp
andhttps
profiles. - Change the HTTP port to
5000
and the HTTPS port to7000
, in theapplicationUrl
properties.
- Remove the
-
Add the following to the
<PropertyGroup>
inGraphQL.csproj
:<RootNamespace>ConferencePlanner.GraphQL</RootNamespace>
-
Add a new directory named
Data
where we will place all of our database-related code:mkdir GraphQL/Data
-
Add a new file
Speaker.cs
in theData
directory using the following code:using System.ComponentModel.DataAnnotations; namespace ConferencePlanner.GraphQL.Data; public sealed class Speaker { public int Id { get; init; } [StringLength(200)] public required string Name { get; init; } [StringLength(4000)] public string? Bio { get; init; } [StringLength(1000)] public string? Website { get; init; } }
-
Add a reference to the following NuGet packages:
Microsoft.EntityFrameworkCore.Relational
version8.0.8
.dotnet add GraphQL package Microsoft.EntityFrameworkCore.Relational --version 8.0.8
Npgsql.EntityFrameworkCore.PostgreSQL
version8.0.4
.dotnet add GraphQL package Npgsql.EntityFrameworkCore.PostgreSQL --version 8.0.4
-
Next, create a new Entity Framework Core DbContext class named
ApplicationDbContext
in theData
directory, using the following code:using Microsoft.EntityFrameworkCore; namespace ConferencePlanner.GraphQL.Data; public sealed class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : DbContext(options) { public DbSet<Speaker> Speakers { get; init; } }
-
Create a
docker-compose.yml
file at the root of the solution, with the following contents, for running a PostgreSQL server:name: graphql-workshop services: graphql-workshop-postgres: container_name: graphql-workshop-postgres image: postgres:16.3 environment: POSTGRES_USER: graphql_workshop POSTGRES_PASSWORD: secret POSTGRES_DB: graphql_workshop networks: [graphql-workshop] ports: ["5432:5432"] volumes: - type: volume source: postgres-data target: /var/lib/postgresql/data networks: graphql-workshop: name: graphql-workshop volumes: postgres-data:
Replace the code in Program.cs
with the following:
using GraphQL.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddDbContext<ApplicationDbContext>(
options => options.UseNpgsql("Host=127.0.0.1;Username=graphql_workshop;Password=secret"));
var app = builder.Build();
app.Run();
Line 7 registers the
ApplicationDbContext
service so that it can be injected into resolvers.
-
Add a reference to the NuGet package
Microsoft.EntityFrameworkCore.Design
version8.0.8
:dotnet add GraphQL package Microsoft.EntityFrameworkCore.Design --version 8.0.8
-
Start the database server using Docker Compose:
docker compose up --detach
-
Install the Entity Framework Core tool (
dotnet-ef
) using the following commands:dotnet new tool-manifest dotnet tool install dotnet-ef --local --version 8.0.8
-
Run the following commands in the command prompt:
dotnet build dotnet ef migrations add Initial --project GraphQL dotnet ef database update --project GraphQL
-
In Visual Studio, select
Tools -> NuGet Package Manager -> Package Manager Console
. -
Run the following commands in the Package Manager Console:
Add-Migration Initial Update-Database
Commands Explained
Command | Description |
---|---|
dotnet ef migrations add Initial / Add-Migration Initial |
Generates code to create the initial database schema based on the model specified in ApplicationDbContext.cs . Initial is the name of the migration. |
dotnet ef database update / Update-Database |
Creates the database. |
If your database ever gets in a bad state and you'd like to reset things, you can use
dotnet ef database drop --project GraphQL
followed bydotnet ef database update --project GraphQL
to remove your database and run all migrations again.
-
Add a reference to the following NuGet packages:
HotChocolate.AspNetCore
version14.0.0-rc.0
.dotnet add GraphQL package HotChocolate.AspNetCore --version 14.0.0-rc.0
HotChocolate.AspNetCore.CommandLine
version14.0.0-rc.0
dotnet add GraphQL package HotChocolate.AspNetCore.CommandLine --version 14.0.0-rc.0
HotChocolate.Types.Analyzers
version14.0.0-rc.0
dotnet add GraphQL package HotChocolate.Types.Analyzers --version 14.0.0-rc.0
-
Set up GraphQL and register our types by adding the following code below
AddDbContext
inProgram.cs
:.AddGraphQLServer() .AddGraphQLTypes();
The above code adds a GraphQL server configuration to the dependency injection container, and registers all types in the assembly using a source generator (
HotChocolate.Types.Analyzers
).Note: The name of the
AddGraphQLTypes
method is based on the assembly name by default, but can be changed using the[Module]
assembly attribute. -
Next we need to configure the GraphQL middleware so that the server knows how to execute GraphQL requests. For this, add the following code below
var app
inProgram.cs
:app.MapGraphQL();
Also, replace
app.Run();
withawait app.RunWithGraphQLCommandsAsync(args);
.Your
Program.cs
should now look like the following:using ConferencePlanner.GraphQL.Data; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services .AddDbContext<ApplicationDbContext>( options => options.UseNpgsql("Host=127.0.0.1;Username=graphql_workshop;Password=secret")) .AddGraphQLServer() .AddGraphQLTypes(); var app = builder.Build(); app.MapGraphQL(); await app.RunWithGraphQLCommandsAsync(args);
-
Create a
Queries
class (Queries.cs
) and add a query that fetches all of our speakers:using ConferencePlanner.GraphQL.Data; using Microsoft.EntityFrameworkCore; namespace ConferencePlanner.GraphQL; public static class Queries { [Query] public static async Task<IEnumerable<Speaker>> GetSpeakersAsync( ApplicationDbContext dbContext, CancellationToken cancellationToken) { return await dbContext.Speakers.ToListAsync(cancellationToken); } }
-
Start the server:
dotnet run --project GraphQL
-
Start Banana Cake Pop or use it built into your browser at http://localhost:5000/graphql/, and connect to our server.
-
Click the
Browse Schema
button, switch to theColumn View
, and navigate toQuery -> speakers
to view the return type of thespeakers
field.
So far we have added a query to our schema, which allows us to query speakers. However, at this point, there is no way to add or modify any data. In this section, we are going to add a mutation for adding new speakers to our database.
For mutations we are using the Relay mutation pattern.
Relay uses a common pattern for mutations, where there are root fields on the mutation type with a single argument,
input
.By convention, mutations are named as verbs, their inputs are the name with
Input
appended at the end, and they return an object that is the name withPayload
appended.
A mutation consists of three components, the input, the payload, and the mutation itself. In our case we want to create a mutation named addSpeaker
.
So, for our addSpeaker
mutation, we create two types: AddSpeakerInput
and AddSpeakerPayload
.
-
Add a file named
AddSpeakerInput.cs
to your project with the following code:namespace ConferencePlanner.GraphQL; public sealed record AddSpeakerInput( string Name, string? Bio, string? Website);
-
Next, we add our
AddSpeakerPayload
, which represents the output of our GraphQL mutation by adding the following code toAddSpeakerPayload.cs
:using ConferencePlanner.GraphQL.Data; namespace ConferencePlanner.GraphQL; public sealed class AddSpeakerPayload(Speaker speaker) { public Speaker Speaker { get; } = speaker; }
-
Now let's add the actual mutation type with our
addSpeaker
mutation in it, to a file namedMutations.cs
:using ConferencePlanner.GraphQL.Data; namespace ConferencePlanner.GraphQL; public static class Mutations { [Mutation] public static async Task<AddSpeakerPayload> AddSpeakerAsync( AddSpeakerInput input, ApplicationDbContext dbContext, CancellationToken cancellationToken) { var speaker = new Speaker { Name = input.Name, Bio = input.Bio, Website = input.Website }; dbContext.Speakers.Add(speaker); await dbContext.SaveChangesAsync(cancellationToken); return new AddSpeakerPayload(speaker); } }
-
Start the server again in order to validate if it is working properly:
dotnet run --project GraphQL
-
Explore the changes to the schema with Banana Cake Pop. There should now be a mutation type and the
addSpeaker
mutation. -
Next, in the
Operation
tabRequest
pane, add a speaker by writing a GraphQL mutation:mutation AddSpeaker { addSpeaker( input: { name: "Speaker name" bio: "Speaker bio" website: "https://speaker.website" } ) { speaker { id } } }
-
Query the names of all the speakers in the database:
query GetSpeakerNames { speakers { name } }
In this first session, you have learned how you can create a simple GraphQL project on top of ASP.NET Core. You have leveraged Entity Framework to create your models and save those to the database. Together, ASP.NET Core, Entity Framework, and Hot Chocolate let you build a simple GraphQL server quickly.