Building GraphQL Playground Server with ASP.NET Core

Samet Çınar
11 min readJul 18, 2022

--

What is GraphQL? What does it do? How is it different from Rest API?

What is GraphQL?

It is API query language.
Used by high-traffic apps like Facebook, Github, Pinterest, Shopify etc.

What does it do?

A schema is determined in the GraphQL project. The client transmits its queries according to this scheme.

  • The client receives only itself necessary data.
  • Great effect on the speed of getting query results.
  • It can be used to provide used between relational entities.
  • Many Rest APIs can be accessed from a single end point.

Example :

Let’s say we are doing a listing process. We have a table named “Order”, that table has 25 properties/fields.

We wrote a new service named “order/getlist” with Rest API for the Order List Page. Let’s say we display data only named “id, totalPrice” during impression. Returning them in json from the service while other features do not have any function on the page will affect my page rendering speed.

That’s why I can get values only named “id, totalPrice” from the service with the GraphQL query.

How is it different from Rest API?

Rest Api vs GraphQL

I found a nice image summarizing the difference from Rest API. Actually that’s summarizing many things..

The Client needs can change over time. In addition to the “id, totalPrice” fields in the example we mentioned above, we will need to make changes to the service when we need the “amount” field. We can be added new field from GraphQL Schema instead of service contract change.

GraphQL eliminate this situation and allow the client to determine the queries by itself.

As an example, I developed GraphQL with .net core. I also used Castle Windsor this too we will be experienced.

You will see “Models, Container, Services, Types, Resolvers, Server” when you open the example project. Before tell in order of These, I want to mention to GraphQL Schema’s structure.

GraphQL Schema

We will use “Types, Queries, Mutation” in the GraphQL Schema. We can mention from “Subscriptions” when it in the next articles.

Types

GraphQL requests a schema to be created with the types it defines. We will most view type named “ObjectGraphType” in our samples.
We have to define all the objects and properties that you use on C# according to the types determined by GraphQL. We will see this in our examples.

Queries
There are the get operations we do on the API. So if the client is creating listing or detail page, it pull to page datas using on “Queries” schema.

Mutations
There are the post/put operations we do on the API. So if the client is creating record add/edit page, it send to data in the page using on “Mutations” schema.

Now we can talk about our project which you downloaded on the GitHub.

Framework versions :
.net core 3.1
GraphQL 3.3.2
Castle Windsor 5.1.1
GraphQL.Server.Ui.Playground 4.2.0

01.Models

01-Models

We will work on three model as “UserDo, OrderDo, OrderDetailDto”. It must be here attention to“IScoppedDependency, ISignletonDependency” that will help us with part IoC(inversion of control).

We will have uses such as those derived from IScopedDependency. We’ll take a closer look at exactly what it does in the next step.

02.Container

02-Container

We need to a container for the dependency method. And we will use “Castle Windsor” for this. You will see “queries, mutations” defined one by one on the Startup.cs when we examine the GraphQL sample. In a large project this is a difficult situation to manage. For this reason, we will use container structure. It will be great sample for you.

Wouldn’t it be none other than Castle Windsor? Of course it can, therefore this layer was designed separately. Here you can use other container framework if you wish.(AutoFac,Ninject etc)

You will see implement “DependencyInstaller” object from a interface named “IWindsorInstaller”. Here you will see a line registering the derived from “IScopedDependency, ISingletonDependency”.

You will see that those derived from IScopedDependency are registered with “Scoped”, and those derived from ISingletonDependency are registered with “Singleton” lifecycle.

As the result, IoCManager will provide us to get concrete objects from the interface we specified with the “Resolve” method.

03.Services

03-Services

I don’t used db connection for service layer. I keep my data in RAM with dummy List which stores instant data. You must be created own service structure.

There can be more than one Rest API. All actions must be developed in this layer for each RestApi. There are interface methods in this my services. We will define them as “IScoppedDependency” and resolve IoCManager.

04.Types

04-Types

We are going to the GraphQL Type part. First of all, “ISingletonGraphType” is very important, we need to derive from “ISingletonDependency” where we talked about earlier parts. Thus, that will be registered in the container and it will give us the opportunity to resolve from IoCManager.

It will help us in the part where we will prevent the types that you will see in GraphQL examples from registered one by one on Startup.

We will create “ObjectGraphType” from Dto objects where we defined to the 01.Models Part. In their constructor part we will decide which objects from Dto to add to the GraphQL schema.

So I don’t have to show each properties from in the DTO. I can decide this here. While doing these definitions, I can also decide on non-mandatory fields.

OrderGraphType

You will see that whole fields define on the OrderDto when we take the OrderGraphType as an example. “DiscountPrice” field can be left so It define to “nullable:true” for this.

I created ObjectGraphType inheritance from the ObjectGraphType and it accept to generic type.I give my DTO object named “OrderDto” in the type section.

I’m doing this transactions in order for the OrderDto, OrderDetailDto and UserDto. Then I need to setup the relationship between them. What’s this?

There may be situations when we want to go user entity from on order entity or we want to order detail entity list get from on order entity

There may be situations when we want to go user entity from on order entity or we want to order detail entity list get from on order entity. We add them to the schema for the client. If client wish take to this data with include process.

Again we going to from OrderGraphType.

OrderGraphType2

We resolve OrderDetailService and UserService through IoCManager.
Calling “user” returns UserGraphType and calling “details” returns OrderDetailGraphType list through currentContext.

We use the ListGraphType because “details” is a list. We use UserGraphType as direct because “user” return a single item. context.Source help us to reach properties where we define in the DTO.

Another GraphQL Type we use is “InputObjectGraphType”. What do we do with the post operations in APIs? We determine the input model and we take this inputModel to mapping our DTO object then we do our process.

This types regard as “InputObjectGraphType”. For this we will get “OrderInputGraphType” as example.

OrderInputGraphType

“OrderInputGraphType” just serve insert operation on this example. For this reason We don’t define id property in here. Thus, I specify that I will only receive “userId, discountPrice and totalPrice” properties during the insert process. At the same time I determine “discountPrice” as “nullable:true” because this property not necessary.

05.Resolvers

05-Resolvers

We will define query and mutation object in here which are both objectGraphType. GraphQLSchema is our main schema, we will define Query and Mutation GraphTypes in this schema. You will see that GraphQLSchema inherit from “Schema”. This object coming us from GraphQL, we can say this is a GraphQLType.

I will give an example for Query ve Mutation then I will tell with detail that how we will define to Schema

Let’s take OrderQuery as an example.

OrderQuery

We make our definitions in constructor when inherit from OrderGraphType. Here we actually decide, which queries should the client access on the Order?

I define two query called “getOrder, getOrders”. We see new type here named “QueryArgument”.

I use “GuidGraphType” because of I am waiting a guid value from page.

Well, What can will be other types?

Guid : GuidGraphType
String : StringGraphType
Int : IntGraphType
Bool : BooleanGraphType

Actually, We can see a lot of GraphQL types that we add GraphType to the end of the types we use in c#.

What we take input model from client side and return to back result model has to be GraphQL type. In Summary, we will use our DTO object in our project side but think of it like we have to tell GraphQL the types it knows about.

Let’s take an example OrderMutation for mutation

Order Mutation

We gave answer to questions about client listing queries in the QueryResolver.
In MutationResolver, we will take the inputModel sent from the page and transmit it to the services, and we will provide registration/update etc. operations.

“insertOrder”: Perform order registration by taking inputModel parameter.

OrderInputGraphType is a type we define, we specify that this is non-nullable with “NonNullGraphType”

We need to send the object we get from the page to our service in the type it knows when sending it to our service, so we cast it to “OrderDto”. This is why we derived the OrderInputGraphType from the generated OrderDto.

We will define to our schema now which this we defined mutations and queries.
You may have seen that OrderQuery is implemented from “IQueryResolver” and OrderMutation is implemented from “IMutationResolver”.

In GraphQLMutation, GraphQLQuery objects, we reveal our schema by introducing an objectGraphType to GraphSchema.

06.Servers

06.Servers

We came to last stage named “GraphQL Playgroud Server”. We use nuget package named “GraphQL.Server.Ui.Playground”. This package provides us with a GraphQLServer that will run in the background and an endpoint from which we can receive requests from the client.

There are two extensions we use in Startup.

ContainerStartupExtension:
We use to register dependencies in the IoCManager.

GraphStartupExtension :

We have to define all list type exclude Query,Mutation(OrderGraphType, OrderInputGraphType etc) as services.AddSignleton()

We collected these types under “ISingletonGraphType” and saved them in one place in the “AddGraphTypes” method. Thus, when a new type arrives, it will only be enough to implement the “ISingletonGraphType” interface.

Since the same situations will be experienced in mutation and query resolvers, we set interfaces for them and saved them in one place with the “AddGraphSchema” method.

It will be enough to implement the “IQueryResolver” interface when a new query arrives, and the “IMutationResolver” interface when a new mutation arrives.

Thus, while developing our project, we will have made our improvements without touching the part that is called the presentation layer in any way. This is a very valuable topic indeed.

Let’s take a look at our example queries and see the benefits GraphQL gives us.

We start our project with f5 by making SCGraphQL.GraphQLServer set as startup project.

In the “Docs” section, we see what queries the client can make. At the same time, we can see the values of all types in the “Schema” section.

Thus, the client can access which questions I can throw, which values I can reach in the query, etc.

First, let’s create a user registration.

Samet Çınar User Mutation

Query :

mutation($inputModel: UserInput!) {
insertUser(inputModel: $inputModel) {
id
name
surname
}
}

Parameter:

{
"inputModel":{
"name":"Samet",
"surname":"Çınar"
}
}

Result :

{
"data": {
"insertUser": {
"id": "29424007-e9d8-4131-8147-8bef39077940",
"name": "Samet",
"surname": "Çınar"
}
},
"extensions": {}
}

Let’s get the list of all user records.

Query: I just want to take “id, name” fields.

query {
getUsers {
id
name
}
}

Result:

{
"data": {
"getUsers": [
{
"id": "29424007-e9d8-4131-8147-8bef39077940",
"name": "Samet"
},
{
"id": "c6f26845-bee1-48fe-9431-59e999735749",
"name": "Test"
}
]
},
"extensions": {}
}

Let’s add surname field in query

query {
getUsers {
id
name
surname
}
}

Result :

{
"data": {
"getUsers": [
{
"id": "29424007-e9d8-4131-8147-8bef39077940",
"name": "Samet",
"surname": "Çınar"
},
{
"id": "c6f26845-bee1-48fe-9431-59e999735749",
"name": "Test",
"surname": "Developer"
}
]
},
"extensions": {}
}

Now let’s add an order to the customer

You should use values where return from your own list because of changed sudden of id values

Query:

mutation($inputModel: OrderInput!) {
insertOrder(inputModel: $inputModel) {
id
}
}

Paramaters:

{
"inputModel":{
"userId":"29424007-e9d8-4131-8147-8bef39077940",
"discountPrice":10,
"totalPrice": 120
}
}

Result:

{
"data": {
"insertOrder": {
"id": "fa80f2c0-87fc-494a-9a98-c0a0bb2fa22a"
}
},
"extensions": {}
}

Now let’s add detail to this order.(orderDetail)

Query :

mutation($inputModel: OrderDetailInput!) {
insertOrderDetail(inputModel: $inputModel) {
id
}
}

Parameters:

{
"inputModel":{
"orderId":"4756edf0-f689-4a07-b053-ea320be2c074",
"productName":"Test Ürünü",
"productPrice": 90
}
}

Result :

{
"data": {
"insertOrderDetail": {
"id": "9cfcd92a-6e73-4c2e-a07d-9431406c2022"
}
},
"extensions": {}
}

Let’s say, I created a lot of orders that include details. Now let’s combine them where under one order list. Let’s take also detail of order and customer information of order while take order list.

Query :

query {
getOrders {
id
user {
id
name
surname
}
details {
productName
productPrice
}
discountPrice
totalPrice
}
}

Result :

{
"data": {
"getOrders": [
{
"id": "fa80f2c0-87fc-494a-9a98-c0a0bb2fa22a",
"user": {
"id": "29424007-e9d8-4131-8147-8bef39077940",
"name": "Samet",
"surname": "Çınar"
},
"details": [
{
"productName": "Test Ürünü",
"productPrice": 90
}
],
"discountPrice": 10,
"totalPrice": 120
},
{
"id": "4756edf0-f689-4a07-b053-ea320be2c074",
"user": {
"id": "c6f26845-bee1-48fe-9431-59e999735749",
"name": "Test",
"surname": "Developer"
},
"details": [
{
"productName": "Test Ürünü",
"productPrice": 90
}
],
"discountPrice": 50,
"totalPrice": 75
}
]
},
"extensions": {}
}

If you want to examine the project codes
Proje kodlarını indirmek isterseniz :

https://github.com/gsmtcnr/SCGraphQL

See you soon..

--

--