GraphQL In .NET Web API With Entity Framework Core - Part One

Why use GraphQL in Web API?

Let’s first understand why we use GraphQL when we directly expose data through a Web API endpoint. Consider a scenario where you want to create endpoints for the User Entity. So, you can expose APIs like GetAllUsers, GetUsersByUserId, and GetUserByUserName to return limited fields like UserName and UserId, not the entire User entity. So again, you need to expose other endpoints, and ultimately, we will end up with n number of endpoints, which is very difficult to maintain. GraphQL helps us here as it’s a schema-definition language. You need to expose only one endpoint, which is expected to be the GraphQL query, and you can get your desired results with a single endpoint.

Step-by-Step Implementation of GraphQL in Web API

Let’s see step by step implementation of GraphQL in Web API.

Create an ASP.NET Core web application and select API as the template and Core 2.0 as the version.

In our demo, we need GraphQL as well as Entity Framework Core, so add the NuGet Packages mentioned below.

  • GraphQL
  • GraphQL.Server.Transports.AspnetCore
  • GraphQL.Server.UI.Playground
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Database Setup

Now, let’s create a database using the MS SQL Server for our demo purposes. Also, create a table and add some dummy data. You can execute the script below to create a table with the data inside the GraphQLDemo database.

USE [GraphQLDemo]
GO
/****** Object:  Table [dbo].[Employee]    Script Date: 2/2/2019 9:15:36 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Employee](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](100) NULL,
    [Email] [varchar](50) NULL,
    [Mobile] [varchar](50) NULL,
    [Company] [varchar](100) NULL,
    [Address] [varchar](100) NULL,
    [ShortDescription] [varchar](1000) NULL,
    [LongDescription] [text] NULL,
 CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Employee] ON
GO
INSERT [dbo].[Employee] ([Id], [Name], [Email], [Mobile], [Company], [Address], [ShortDescription], [LongDescription]) VALUES (1, N'Akshay', N'[email protected]', N'9999999999', N'Dotnetbees', N'Hyderabad', N'Short Description', N'Long Description')
GO
INSERT [dbo].[Employee] ([Id], [Name], [Email], [Mobile], [Company], [Address], [ShortDescription], [LongDescription]) VALUES (2, N'Panth', N'[email protected]', N'8888888888', N'Radix', N'Vadodara', N'SD', N'LD')
GO
SET IDENTITY_INSERT [dbo].[Employee] OFF
GO

Connection String Setup

In the next step, we need a connection string to connect with the database. So, as a normal practice, let’s store our connection string in Appsettings.json.

Appsettings.json

"ConnectionStrings": {
    "DefaultConnection": "Server=akshay-pc\\devsql2016;Database=GraphQLDemo;Trusted_Connection=True;MultipleActiveResultSets=true"
}

Scaffold Database

Run the scaffold command to generate the model and dbcontext class.

Open the Package Manager Console and execute the below command.

Scaffold-DbContext “Server=AKSHAY-PC\DEVSQL2016;Database=GraphQLDemo;Trusted_Connection=True;” Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models.

Employee.cs

namespace GraphQLInWebApiCore
{
    public partial class Employee
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Mobile { get; set; }
        public string Company { get; set; }
        public string Address { get; set; }
        public string ShortDescription { get; set; }
        public string LongDescription { get; set; }
    }
}

GraphQLDemoContext

using Microsoft.EntityFrameworkCore;
namespace GraphQLInWebApiCore
{
    public partial class GraphQLDemoContext : DbContext
    {
        public GraphQLDemoContext()
        {
        }
        public GraphQLDemoContext(DbContextOptions<GraphQLDemoContext> options)
            : base(options)
        {
        }

        public virtual DbSet<Employee> Employee { get; set; }
    }
}

DbContext configuration

Add the DbContext under ConfigureServices in Startup.cs, which adds to the service collection and can be injected whenever required.

Startup.cs

services.AddDbContext<GraphQLDemoContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

Create Employee Repository

Create an employee repository to get all the employees from the database through dbcontext, i.e., Entity Framework Core.

IEmployeeRepository.cs

using System.Collections.Generic;
using System.Threading.Tasks;
namespace GraphQLInWebApiCore
{
    public interface IEmployeeRepository
    {
        Task<List<Employee>> GetEmployees();
    }
}

EmployeeRepository.cs

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace GraphQLInWebApiCore
{
    public class EmployeeRepository : IEmployeeRepository
    {
        private readonly GraphQLDemoContext _context;
        public EmployeeRepository(GraphQLDemoContext context)
        {
            _context = context;
        }

        public Task<List<Employee>> GetEmployees()
        {
            return _context.Employee.ToListAsync();
        }
    }
}

So far, we are done with

  • Creating a table in DB
  • Adding sample data to the table
  • Configuring Entity Framework Core and setting the connection with a database
  • Creating a repository that will return the list of employees

Implement GraphQL Types

Let’s start implementing GraphQL. This requires Schema, Query, and ObjectGraphType.

Schema

We need to create EmployeeType, which inherits ObjectGraphType<T>, and set all the fields of an employee in the constructor.

using GraphQL.Types;
namespace GraphQLInWebApiCore
{
    public class EmployeeType : ObjectGraphType<Employee>
    {
        public EmployeeType()
        {
            Field(a => a.Id);
            Field(a => a.Name);
            Field(a => a.Email);
            Field(a => a.Mobile);
            Field(a => a.Company);
            Field(a => a.Address);
            Field(a => a.ShortDescription);
            Field(a => a.LongDescription);
        }
    }
}

Create a query that will set the field of the previously created object graph type internally, fetch the data from the repository, and resolve the context.

using GraphQL.Types;
namespace GraphQLInWebApiCore
{
    public class EmployeeQuery : ObjectGraphType
    {
        public EmployeeQuery(IEmployeeRepository employeeRepository)
        {
            Field<ListGraphType<EmployeeType>>(
                "employees",
                resolve: context => employeeRepository.GetEmployees()
            );
        }
    }
}

Schema will be used to resolve the query. We will resolve the previously created query; i.e., EmployeeQuery.

using GraphQL;
using GraphQL.Types;
namespace GraphQLInWebApiCore
{
    public class EmployeeSchema : Schema
    {
        public EmployeeSchema(IDependencyResolver resolver) : base(resolver)
        {
            Query = resolver.Resolve<EmployeeQuery>();
        }
    }
}

Dependency Injection

Add the below code snippet under configureservices in startup.cs, which will be used to resolve the dependency. That means we are adding interfaces and concrete implementations against each interface inside the service collection.

services.AddScoped<IEmployeeRepository, EmployeeRepository>();
// GraphQL configuration
services.AddScoped<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService));
services.AddScoped<EmployeeSchema>();
services.AddGraphQL(o => { o.ExposeExceptions = false; })
        .AddGraphTypes(ServiceLifetime.Scoped);

Add the below code under the configure method in startup.cs. With the UseGraphQL method, we can set the path to access GraphQL in the parameter. But if you don’t set it, it will consider the /graphql path.

app.UseGraphQL<EmployeeSchema>();
app.UseGraphQLPlayground(new GraphQLPlaygroundOptions());

At the starting stage, we added a NuGet package called GraphQL.Server.UI.Playground which will provide the UI where we can write our GraphQL queries and at the same time, we can see the result. For that, we need to browse the UI/playground path. We can configure the same at the launch of the browser.

Debug

Now, run the application and you can see that the UI is rendered in the browser where on the left side, we have a query input section and on the right side, the result section. In the middle, we have an "Execute" button to execute the query. If you click on the Schema button which is on the extreme right side of the browser, you can see the query and graph object type. This detail will help to write the query.

New tab

As soon as you start writing a query, IntelliSense will suggest the query and object graph type that we have created.

Employees

Name

Click the "Run" button, and you can see the result, i.e., the list of employees on the right side. If you observe the query and result, we ask for the name and email fields of employees, and we get the same as the result. This means we can pass a response parameter that we would like to return aa a result, and we will only get that.

Employees

In the object graph type, we can add the description as well so that a user can understand the field better. Here, we have added the description with the company field.

using GraphQL.Types;
namespace GraphQLInWebApiCore
{
    public class EmployeeType : ObjectGraphType<Employee>
    {
        public EmployeeType()
        {
            Field(a => a.Id);
            Field(a => a.Name);
            Field(a => a.Email);
            Field(a => a.Mobile);
            Field(a => a.Company).Description("Company Name");
            Field(a => a.Address);
            Field(a => a.ShortDescription);
            Field(a => a.LongDescription);
        }
    }
}

Once you run the application, you can see the description for that particular field in the playground UI.

Company

Now, we might have a question about how we can use GraphQL inside the API and expose it through the endpoint.

To use GraphQL, we need to add the GraphQL.Client NuGet package.

Create an Employee controller and create one GET method inside that.

Initialize GraphQLClient with GraphQL URL

Create an instance of GraphQLRequest and write the same query that we tried in the playground UI.

Call the PostAsync method of GraphQLClient, and you will get the response.

Convert that response to the List of Employees and return it.

using GraphQL.Client;
using GraphQL.Common.Request;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace GraphQLGraphTypeFirstSingleTable.Controllers
{
    [Route("Employee")]
    public class EmployeeController : Controller
    {
        [HttpGet]
        public async Task<List<Employee>> Get()
        {
            using (GraphQLClient graphQLClient = new GraphQLClient("http://localhost:64034/graphql"))
            {
                var query = new GraphQLRequest
                {
                    Query = @"
                    {
                        employees    
                        {
                            name email
                        }
                    }",
                };
                var response = await graphQLClient.PostAsync(query);
                return response.GetDataFieldAs<List<Employee>>("employees");
            }
        }
    }
}

Run the application and open Postman to verify the preceding API. Select GET as the method and add the API URL to call the Employee Controller GET method.

Click on the "Send" button and you can see the list of employees.

History

In this article, we saw how to use GraphQL with one table without argument. In the next part, we will see how we can pass the argument in a GraphQL query.

You can download the sample from here.