0% found this document useful (0 votes)
8 views

GraphQL

Uploaded by

logon2sudarsh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

GraphQL

Uploaded by

logon2sudarsh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Developing API In .

NET Core With GraphQL

Introduction
GraphQL is a query language for APIs that provides a more efficient and flexible
alternative to REST. It was originally built by Facebook but it’s open-sourced and is
maintained by a large community.

To design web APIs, Restful architecture has become the standard over a couple of
years. However, REST APIs have shown to be too inflexible to keep up with the
rapidly changing requirements of the clients that access them.

To solve many of the shortcomings and inefficiencies that developers experience


when interacting with REST APIs, GraphQL was developed to cope with the need for
more flexibility and efficiency. So, GraphQL is nothing but a better REST.

In REST, we generally have multiple endpoints to perform CRUD operations on an


entity and also there are overfetching and underfetching problems and it returns
fixed data structures which is a little inflexible in nature.

• Overfetching means that endpoints return additional information that’s


not needed in the UI.
• Underfetching means that a specific endpoint doesn’t provide enough of
the required information. The client will have to make an additional call
to fetch everything it needs.

Let’s consider TechEvent as an entity - A tech event can have multiple participants
and similarly, a participant can enroll in multiple tech events. Here you need to call 3
endpoints to fetch the required data in REST.

GET /api/techEvents => To get all tech events


GET /api/techEvents/{id} => To get single tech event info by id
GET /api/techEvents/{id}/participants => To get participants details
for an event
VB.Net

Copy

But using GraphQL, a single endpoint POST/graphql will be sufficient to archive this
data requirement instead of 3 different endpoints and we can do it by just modifying
query as below.
{
"query": "query{ event(eventId:1){ eventId speaker }}"
}
JSON

Copy

{
"query": "query { events { eventId eventName participants {
participantName phone } } }"
}
JSON

Copy

Below Illustration of Rest API vs GraphQL with respect to endpoints.

Related reads
Part II - Preforming CRUD Operations Using GraphQL In ASP.NET Core
Implementation of GraphQL with ASP.Net core
In this article, we're going to build a GraphQL server from scratch. The server will
expose a TechEvent management graph QL endpoint which will allow querying on
data.

For demo purposes, let’s create a local DB called “TechEventDB” in an MS SQL server
(or you can use InMemoryDatabase) and add the below tables with some dummy
data.

1. Table - TechEventInfo: This table consists of technical event information


like event ID, name, speaker, etc.
2. Table - Participant: This table consists of participant information like
name, phone, email, etc.
3. Table - EventParticipants: This is a mapping table b/w event and
participants with many to many relationships.
CREATE TABLE dbo.TechEventInfo(
EventId int IDENTITY(1,1) NOT NULL,
EventName varchar(100) NOT NULL,
Speaker varchar(100) NOT NULL,
EventDate Date NULL
CONSTRAINT [PK_TechEventInfo] PRIMARY KEY CLUSTERED
(
EventId ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SQL

Copy

CREATE TABLE dbo.Participant(


ParticipantId int IDENTITY(1,1) NOT NULL,
ParticipantName varchar(100) NOT NULL,
Email varchar(100) NOT NULL,
Phone varchar(20) NULL,
CONSTRAINT [PK_Participant] PRIMARY KEY CLUSTERED
(
ParticipantId ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON
[PRIMARY]
) ON [PRIMARY]
SQL

Copy

CREATE TABLE [dbo].EventParticipants


(
EventParticipantId INT NOT NULL IDENTITY(1,1),
EventId INT NOT NULL,
ParticipantId INT NULL,
CONSTRAINT [PK_EventParticipants] PRIMARY KEY CLUSTERED
(
EventParticipantId ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY],
CONSTRAINT [FK_EventParticipants_TechEventInfo_EventId] FOREIGN KEY
(EventId) REFERENCES [TechEventInfo] (EventId),
CONSTRAINT [FK_EventParticipants_Participant_ParticipantId] FOREIGN
KEY ([ParticipantId]) REFERENCES [Participant] ([ParticipantId])
) ON [PRIMARY];
SQL

Copy

Now we have to insert some sample data into all the tables.

Once we are done with these steps, we can create an ASP.NET core WebAPI project
called “GraphQL.API” and add a DB connection string in appsettings.json.

{
"ConnectionStrings": {
"GraphQLDBConnection": "Server=Anupam-
PC\\SQLEXPRESS;Database=TechEventDB;Trusted_Connection=True;MultipleAct
iveResultSets=true"
}
}
JSON

Copy

Add the DbContext under ConfigureServices in Startup. cs.

services.AddDbContext<TechEventDBContext>(options =>

options.UseSqlServer(Configuration.GetConnectionString("GraphQLDBConnec
tion")));
C#

Copy

To generate the entity context class, now we need to run the scaffold command
from the package manager console (Tools => Nuget Package Manager => Package
Manager Console) to generate the dbContext class using Entity Framework Core.
Create a folder called Infrastructure and subfolder called DBContext into the project.

Scaffold-DbContext "Server=Anupam-
PC\SQLEXPRESS;Database=GraphQLDemo;Trusted_Connection=True;"
Microsoft.EntityFrameworkCore.SqlServer -OutputDir
Infrastructure\DBContext
SQL

Copy

After successful execution of the Scaffold command, entity, and context will be
added as below.
Now create a Repositories folder where we can handle CRUD operation on tech
event entity.

ITechEventRepository.cs
using GraphQL.API.Infrastructure.DBContext;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace GraphQL.API.Infrastructure.Repositories
{
public interface ITechEventRepository
{
Task<TechEventInfo[]> GetTechEvents();
Task<TechEventInfo> GetTechEventById(int id);
Task<List<Participant>> GetParticipantInfoByEventId(int id);
}
}
C#

Copy

TechEventRepository.cs
using GraphQL.API.Infrastructure.DBContext;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GraphQL.API.Domain;
namespace GraphQL.API.Infrastructure.Repositories
{
/// <summary>
/// TechEventRepository.
/// </summary>
public class TechEventRepository : ITechEventRepository
{
/// <summary>
/// The _context.
/// </summary>
private readonly TechEventDBContext _context;

public TechEventRepository(TechEventDBContext context)


{
this._context = context;
}
public async Task<List<Participant>>
GetParticipantInfoByEventId(int id)
{
return await (from ep in this._context.EventParticipants
join p in this._context.Participant on
ep.ParticipantId equals p.ParticipantId
where ep.EventId == id
select p).ToListAsync();
}
public async Task<TechEventInfo> GetTechEventById(int id)
{
return await
Task.FromResult(_context.TechEventInfo.FirstOrDefault(i => i.EventId ==
id));
}

public async Task<TechEventInfo[]> GetTechEvents()


{
return _context.TechEventInfo.ToArray();
}
}
}
C#

Copy

Register DI on Startup. cs for Repository.

services.AddTransient<ITechEventRepository, TechEventRepository>();
C#

Copy

So far, we've created our DB context and repository. It's time to start using GraphQL
integration in our project, so we can get our GraphQL server running.

Add the below NuGet packages into the API project.


<PackageReference Include="GraphQL" Version="2.4.0" />
<PackageReference Include="graphiql" Version="1.2.0" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore"
Version="3.4.0" />
XML

Copy

First, we're going to configure the GraphQL schema step by step as mentioned
below:

Step 1. Create GraphQL types.

To admit through our endpoint to our GraphQL clients.

Step 2. Create a GraphQL query object

To allows us to define the queries that will then surface to the clients which they can
then issue against our endpoint.

Step 3. Create a schema object to expose the query

To allow tools like graphical to inspect and see what types are available. It's also
necessary to enable GraphQL clients.

Step 4. Register all types in Startup.cs

To register all of those types with our ASP.NET core IOC container.

Add a folder into a project called “GraphqlCore” – where we will keep GraphQL-
related Type, Schema, Query files, etc.

Create GraphQL types


Create TechEventInfoType.cs which inherits from ObjectGraphType<TechEventInfo>
and set all the fields into the constructor.

•ObjectGraphType <T>: Used to expose GraphQL types in our schema,


“T” here is the model.
• ListGraphType <T>: Used to define GraphQL Collection.
using GraphQL.API.Infrastructure.DBContext;
using GraphQL.API.Infrastructure.Repositories;
using GraphQL.Types;

namespace GraphQL.API.GraphqlCore
{
public class TechEventInfoType : ObjectGraphType<TechEventInfo>
{
public TechEventInfoType(ITechEventRepository repository)
{
Field(x => x.EventId).Description("Event id.");
Field(x => x.EventName).Description("Event name.");
Field(x => x.Speaker).Description("Speaker name.");
Field(x => x.EventDate).Description("Event date.");

Field<ListGraphType<ParticipantType>>(
"participants",
arguments: new QueryArguments(new
QueryArgument<IntGraphType> { Name = "eventId" }),
resolve: context =>
repository.GetParticipantInfoByEventId(context.Source.EventId)
);
}
}
}
C#

Copy

Here, Field() is nothing but used to expose to the client If you have any specific
domain property that you don’t want to expose – don’t need to add to the
constructor. Also, we can set a description of each field. Those descriptions will
actually populate back to the client when they use graphical and they view the
schema.

In this TechEventInfoType, we added a Field called “participants” as we want to


expose participants along with events and the Field will be like

Field<ListGraphType<ParticipantType>>(Name, Arguments, ResolveFunc)


C#

Copy

Name (i.e. “participants”) is basically the name of the field. Arguments (e.g. “eventId”)
are nothing but used as input to the resolver function. The resolve function is going
to get invoked in GetParticipantInfoByEventId() to retrieve participants from the
repository.

Similarly, for Participants, we need to create ParticipantType.cs

using GraphQL.API.Infrastructure.DBContext;
using GraphQL.Types;

namespace GraphQL.API.GraphqlCore
{
public class ParticipantType : ObjectGraphType<Participant>
{
public ParticipantType()
{
Field(x => x.ParticipantId).Description("Participant id.");
Field(x => x.ParticipantName).Description("Participant
name.");
Field(x => x.Email).Description("Participant Email
address.");
Field(x => x.Phone).Description("Participant phone
number.");
}
}
}
C#

Copy

Create a GraphQL query object


Now we're going to create our query which will be exposed to the client.

1. Return a TechEventInfo based on Id.


2. Return a list of TechEventInfo.

Here, ObjectGraphType<object> we're just going to put object and that's because we
don't have an existing class that we're mapping to.

using GraphQL.API.Infrastructure.Repositories;
using GraphQL.Types;
namespace GraphQL.API.GraphqlCore
{
public class TechEventQuery : ObjectGraphType<object>
{
public TechEventQuery(ITechEventRepository repository)
{
Name = "TechEventQuery";

Field<TechEventInfoType>(
"event",
arguments: new QueryArguments(new
QueryArgument<IntGraphType> { Name = "eventId" }),
resolve: context =>
repository.GetTechEventById(context.GetArgument<int>("eventId"))
);

Field<ListGraphType<TechEventInfoType>>(
"events",
resolve: context => repository.GetTechEvents()
);
}
}
}
C#

Copy

Create a schema object to expose the query


The schema will be used to resolve the query. We will resolve the previously created
query; i.e., TechEventQuery.cs, and a dependency resolver is going to be necessary
in order for dependency injection to work.

using GraphQL.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GraphQL.API.GraphqlCore
{
public class TechEventSchema : Schema
{
public TechEventSchema(IDependencyResolver resolver)
{
Query = resolver.Resolve<TechEventQuery>();
DependencyResolver = resolver;
}
}
}
C#

Copy

Register all types in Startup.cs

Now start registering the types, queries, and Schema that we created so far. To do
this, add the below code snippet under configure services in startup. cs.

services.AddSingleton<TechEventInfoType>();
services.AddSingleton<ParticipantType>();
services.AddSingleton<TechEventQuery>();
var sp = services.BuildServiceProvider();
services.AddSingleton<ISchema>(new TechEventSchema(new
FuncDependencyResolver(type => sp.GetService(type))));
C#

Copy
Then before the app.UseMvc(); add the following line in the configure method.

app.UseGraphiQl("/graphql");
C#

Copy

Web API Controller


You can now create a GraphQLController with a single action method/endpoint that
handles every incoming query that our schema supports. The client will always be
sending the POST request which will contain the query name, operation name, and
the variables. You can create a new class called GraphqlQuery.cs that will serve as a
model for all queries from the client.

GraphqlQuery.cs
using Newtonsoft.Json.Linq;
namespace GraphQL.API.GraphqlCore
{
public class GraphqlQuery
{
public string OperationName { get; set; }
public string NamedQuery { get; set; }
public string Query { get; set; }
public JObject Variables { get; set; }
}
}
C#

Copy

GraphQLController.cs
using System.Threading.Tasks;
using GraphQL.API.GraphqlCore;
using GraphQL.Types;
using Microsoft.AspNetCore.Mvc;

namespace GraphQL.API.Controllers
{
[Route("[controller]")]
[ApiController]
public class GraphQLController : ControllerBase
{
private readonly IDocumentExecuter _documentExecuter;
private readonly ISchema _schema;
public GraphQLController(ISchema schema, IDocumentExecuter
documentExecuter)
{
_schema = schema;
_documentExecuter = documentExecuter;
}
[HttpPost]
public async Task<IActionResult> PostAsync([FromBody]
GraphqlQuery query)
{
if (query == null) { throw new
ArgumentNullException(nameof(query)); }
var inputs = query.Variables.ToInputs();
var executionOptions = new ExecutionOptions
{
Schema = _schema,
Query = query.Query,
Inputs = inputs
};
var result = await
_documentExecuter.ExecuteAsync(executionOptions);
if (result.Errors?.Count > 0)
{
return BadRequest(result);
}
return Ok(result);
}
}
}
C#

Copy

Add below in startup. cs.

services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
C#

Copy

In REST, as a rule, we use the HTTP GET verb to fetch data. In GraphQL we can
certainly still use GET requests for fetching data however that means we must store
our "query" in the query string of the URL ie. api/graphql?query=.... A cleaner
approach is to send the query in the JSON-encoded body of a POST request.

At the starting stage, we added a NuGet package called GraphiQL 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 graphql path. We can configure the same
at the launch of the browser.
Now we are done with the demo project, let’s see the overall folder and file structure
of it.

You might also like