DEV Community 👩‍💻👨‍💻

Cover image for Getting started with GraphQL in .NET 6 - Part 2 (Query + Mutation to Database)
Bervianto Leo Pratama
Bervianto Leo Pratama

Posted on

Getting started with GraphQL in .NET 6 - Part 2 (Query + Mutation to Database)

Welcome to our second part to learn more about GraphQL! I'm so excited about GraphQL. Since, I just learn this maybe about last 1-3 months. I hope you can give me some advises or some suggestions about my articles. Let's go, we learn more the GraphQL.

Prepare your tools

  1. Since .NET 6 finally released and VS 2022 released too. I use VS 2022 to help me more about Database. But, don't worry, if you use Visual Studio Code, you still can follow step by step, I will bring you some extra steps.

  2. Install SQL Server. From here - if you more familiar with Docker, I suggest you to use the docker, they support in the Linux, check here. That is why I suggest you to use Docker instead, for Linux user. Note: If you want to try another databases, feel free to choose your favorite database. You will need to update some code, like dependencies and when settings the DbContext.

Install Dependencies

Your final code (GraphQLNetExample.csproj) will be like this:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="GraphQL" Version="4.6.1" />
    <PackageReference Include="GraphQL.MicrosoftDI" Version="4.6.1" />
    <PackageReference Include="GraphQL.Server.Authorization.AspNetCore" Version="5.0.2" />
    <PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="5.0.2" />
    <PackageReference Include="GraphQL.Server.Ui.Altair" Version="5.0.2" />
    <PackageReference Include="GraphQL.SystemTextJson" Version="4.6.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  </ItemGroup>

</Project>
Enter fullscreen mode Exit fullscreen mode

We are installing some dependencies about EntityFrameworkCore. The manual step is like this (if you use dotnet cli):

  1. dotnet add GraphQLNetExample package Microsoft.EntityFrameworkCore.Design
  2. dotnet add GraphQLNetExample package Microsoft.EntityFrameworkCore.SqlServer - feel free to change with your favorite database.
  3. dotnet add GraphQLNetExample package Microsoft.EntityFrameworkCore.Design

Prepare our databases

  • Create DbContext. My side, write at EntityFramework/NotesContext.cs.
using GraphQLNetExample.Notes;
using Microsoft.EntityFrameworkCore;

namespace GraphQLNetExample.EntityFramework
{
    public class NotesContext : DbContext
    {
        public DbSet<Note> Notes { get; set; }

        public NotesContext(DbContextOptions options) : base(options)
        {

        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Update Notes/Note.cs, in this case, I add Required annotation.
using System.ComponentModel.DataAnnotations;

namespace GraphQLNetExample.Notes;

public class Note
{
    public Guid Id { get; set; }
    [Required]
    public string Message { get; set; }
}
Enter fullscreen mode Exit fullscreen mode
  • Update Program.cs, we register the DbContext. Again, feel free to setup with your favorite database.
// ... another existing code

// Add services to the container.
builder.Services.AddDbContext<NotesContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("Default"));
});
builder.Services.AddSingleton<ISchema, NotesSchema>(services => new NotesSchema(new SelfActivatingServiceProvider(services)));

// ... another existing code
Enter fullscreen mode Exit fullscreen mode
  • Update appsettings.json, to add the Connection String. Please update the database, User, and Password section with your server configuration.
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Default": "Server=localhost;Database=graphqltutorial;User Id=sa;Password=;"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Don't forget to create your database in SQL Server.

  • Add Migration. Because I use Visual Studio 2022, so I can use Add-Migration BaseNoteModel, run this command at Package Manager Console. How to navigate? Tools > NuGet Package Manager > Package Manager Console.

Add Migration

Note: If you use dotnet ef & dotnet cli, please refer to this. In that post, I provide you some steps to use the dotnet cli & dotnet ef with dotnet tools.

  • Update database. When use Visual Studio, run this: Updata-Database, to make our database sync with the current migration.

Update Database

  • Yey, your database is ready!

Update Query & Add a Mutation

  • Create a Mutation file, Notes/NotesMutation.cs. We use string type because we only have 1 field only, but if we have larger columns, I suggest to write our input type.
using GraphQL;
using GraphQL.Types;
using GraphQLNetExample.EntityFramework;

namespace GraphQLNetExample.Notes
{
    public class NotesMutation : ObjectGraphType
    {
        public NotesMutation()
        {
            Field<NoteType>(
                "createNote",
                arguments: new QueryArguments(
                    new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "message"}
                ),
                resolve: context =>
                {
                    var message = context.GetArgument<string>("message");
                    var notesContext = context.RequestServices.GetRequiredService<NotesContext>();
                    var note = new Note
                    {
                        Message = message,
                    };
                    notesContext.Notes.Add(note);
                    notesContext.SaveChanges();
                    return note;
                }
            );
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Update our query: Notes/NotesQuery.cs. Our final query will looks like this:
using GraphQL.Types;
using GraphQLNetExample.EntityFramework;

namespace GraphQLNetExample.Notes;

public class NotesQuery : ObjectGraphType
{
    public NotesQuery()
    {
        Field<ListGraphType<NoteType>>("notes", resolve: context => new List<Note> {
          new Note { Id = Guid.NewGuid(), Message = "Hello World!" },
          new Note { Id = Guid.NewGuid(), Message = "Hello World! How are you?" }
        });
        Field<ListGraphType<NoteType>>("notesFromEF", resolve: context =>
        {
            var notesContext = context.RequestServices.GetRequiredService<NotesContext>();
            return notesContext.Notes.ToList();
        }
        );
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Register our Mutation to Schema. Update Notes/NotesSchema.cs.
using GraphQL.Types;

namespace GraphQLNetExample.Notes;

public class NotesSchema : Schema
{
    public NotesSchema(IServiceProvider serviceProvider) : base(serviceProvider)
    {
        Query = serviceProvider.GetRequiredService<NotesQuery>();
        Mutation = serviceProvider.GetRequiredService<NotesMutation>();
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Yes, your GraphQL is ready!

Test our GraphQL

  • I will test from mutation part first.
mutation
{
  createNote(message: "Hello World!")
  {
      id
      message
  }
}
Enter fullscreen mode Exit fullscreen mode

Test Mutation

  • Now, we try to test our query. I add original (in memory), to check the different.
{
  notesFromEF {
    id
    message
  }
  notes {
    id
    message
  }
}
Enter fullscreen mode Exit fullscreen mode

Test Query

Thank you

For the repository, you can visit here:

GraphQL .NET Example

GraphQL example implementation in .NET 6.

LICENSE

MIT

I suggest you to learn more about data access layer. You can learn from here. So, hopefully you don't touch DbContext directly. I touch DbContext directly because this is still simple application and small project, if the project more larger, you will need the data access layer.

I'm not sure yet for the third part. Yes, we will have other parts, but not sure yet. Either I will add Authentication/Authorization parts, or just move to how we call the GraphQL in FrontEnd side, I will use the React.js for this. If you have a suggestion, feel free to comment here.

Finally, thank you for your attention and read until this section. Have great days!

Thank you

Top comments (6)

Collapse
 
francescoosato profile image
francescoosato

Running your github code I get the following exception:

InvalidOperationException: Cannot execute request if no query is specified
GraphQL.DocumentExecuter.ExecuteAsync(ExecutionOptions options) in DocumentExecuter.cs
GraphQL.Server.DefaultGraphQLExecuter.ExecuteAsync(string operationName, string query, Inputs variables, IDictionary context, IServiceProvider requestServices, CancellationToken cancellationToken) in DefaultGraphQLExecuter.cs
GraphQL.Server.Transports.AspNetCore.GraphQLHttpMiddleware.InvokeAsync(HttpContext context) in GraphQLHttpMiddleware.cs
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Any idea?
Thanks

Collapse
 
berviantoleo profile image
Bervianto Leo Pratama

Do you send any queries?

I've tried with valid query and don't have any problems.

Altair

You can use (your ip)/ui/altair to try the GraphQL.

You will get that error when try to access directly without send any "query".

Access Directly

Collapse
 
francescoosato profile image
francescoosato

Sorry it was my mistake. Your solution works properly.

Thread Thread
 
berviantoleo profile image
Bervianto Leo Pratama

You don't need to be sorry. It's great when people ask me to solve their problems.

Collapse
 
cairocafe profile image
bleskop stevens

How do I use multiple schemas?

Collapse
 
berviantoleo profile image
Bervianto Leo Pratama

How about this sample: github.com/graphql-dotnet/graphql-...?

Hey 😍

Want to help the DEV Community feel more like a community?

Head over to the Welcome Thread and greet some new community members!

It only takes a minute of your time, and goes a long way!