Using GraphQL with C#

Using GraphQL with C#

An application demonstrating use of Graphql with C#.

In todays newsletter we will look into how can we use GraphQL with C#. By the end of this article you will be able to use GraphQL with C#. We are going to cover the following topics.

  1. What is GraphQL?
  2. What problem does it solve?
  3. Components of GraphQL
  4. Demo application using GraphQL and C#

What is GraphQL?

GraphQL is a query language for your APIs that can be used to get only the required information. It allows you to query for exactly the fields you want solving the problem of over fetching and under fetching.

What problem it solves?

The GraphQL solves the following problems.

  • Over fetching and under fetching of data
  • GraphQL is database neutral technology that provides flexibility to the client to get data from multiple servers in a single response.
  • Development is faster due to the fact that client has more flexibility in fetching the data.
  • A single query can return response with multiple resources saving the cost of multiple calls.
  • As client can request exactly the what it needs results in improving the performance of application.
  • It includes in built support for real time updates with subscriptions.
  • GraphQL APIs are self documenting resulting the developers to explore the schema.

Components of GraphQL

The GraphQL consists of the following components:

  1. Schema: This is the most important component of GraphQL. It describes the types of data provided by the API, the relationships between these types, and the operations that can be performed.
  2. Query: This is a read operation in GraphQL. Clients use queries to request specific data from the API.
  3. Mutation: This is a write operation in GraphQL. Clients use mutations to create, update, or delete data.
  4. Subscription: This is a real-time operation in GraphQL. Clients use subscriptions to receive real-time updates from the server.
  5. Resolver: This is a function that connects a GraphQL query to its data source. Resolvers are responsible for fetching the data for individual fields in a schema.
  6. Type System: GraphQL uses a strong type system to define the capabilities of an API. All the types that are possible to send and receive from an API are defined in advance.

Demo using GraphQL and C#

Setup

  1. Create a solution using any IDE of your choice. I am using visual studio 2022.
  2. Create a console application.
  3. Install the GraphQL NuGet package

Create a solution

Use the following commands in command prompt to create a folder and a solution file.

mkdir GraphQLDemo
cd GraphQLDemo
// create a new solution project
dotnet new sln        

Create a console application

Type the following command to create a console application.

dotnet new console -o DemoApp
cd DemoApp        

Adding the graphql Nuget package

dotnet add package GraphQL        

Start adding code

Copy paste the below code snippet to replace Program.cs file. The code below is a basic demonstration of defining the Types, Queries and Schema execution.

using GraphQL.SystemTextJson;
using GraphQL.Types;
using GraphQLDemo;
using System.Text.RegularExpressions;

public class Program
{
    public static async Task Main(String[] args)
    {
        var schema = Schema.For(@" 
        type Employee{
            name: String,
            age: Int,
            salary: Float,
            isMarried: Boolean,
            designation: String,
            address: String,
            email: String,
            phone: String,
            skills: [String]
        }
         type Query{
            employees:[Employee]
        }
        
        ", _ =>
        {
            _.Types.Include<Query>();

        });
        var json = await schema.ExecuteAsync(_ =>
        {
            _.Query = "{employees{name,age,skills}}";

        });
        Console.WriteLine(Regex.Unescape(json));
    }
}        

Lets discuss what is happening in the above code:

Declaring the schema - The is schema is defined using schema.For(). Here the schema defines two types namely Query and Employee. Employee is an object type having fields like name, age, salary etc.

Declaring the types - We are defining a type as Employee and defining its properties under { }. Then we add employees to the Query and say its of type [Employee] meaning Employee array. The second argument of schema.For() means that we will define a class Query that will handle all incoming requests. Here Query class is resolvers in GraphQL.

_.Types.Include<Query>();        

Lets create Query class as shown below:

using GraphQL;

namespace GraphQLDemo;

public class Query
{
    [GraphQLMetadata("employees")]
    public IEnumerable<Employee> GetEmployees()
    {
        return CompanyDB.GetEmployees();
    }
}        

This Query class is responsible to handle anything inside Query in our schema. That will be employees. So, we will define a method called GetEmployees() that will return the list of employees from an in memory database called CompanyDB. CompanyDB and Employee will be defined as shown below.

namespace GraphQLDemo;

public class CompanyDB
{
    public static IEnumerable<Employee> GetEmployees()
    {
        var result = new List<Employee>()
        {
            new Employee() {Name = "Luke", Age = 30, Skills = new List<string>{"Python","C","ML"}},
            new Employee() {Name = "Yoda", Age = 23,Skills =new List<string> {"Go","C++","React"}},
            new Employee() {Name = "Darth Vadar", Age = 35,Skills = new List<string>{"Java","C#","React"}}
        };
        return result;
    }


}
public class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }
    public float Salary { get; set; }
    public bool IsMarried { get; set; }
    public string Designation { get; set; }
    public string Address { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public List<string> Skills { get; set; }
}        

Next we will define what we want our Query to return in the code we define as :

{employees {name, age, skills} }        

This is similar to SQL query

select name, age, skills
from employees;         

Executing the query to return response in json format. Finally when we run the console application we will see the following output:

{
  "data": {
    "employees": [
      {
        "name": "Luke",
        "age": 30,
        "skills": [
          "Python",
          "C",
          "ML"
        ]
      },
      {
        "name": "Yoda",
        "age": 23,
        "skills": [
          "Go",
          "C++",
          "React"
        ]
      },
      {
        "name": "Darth Vadar",
        "age": 35,
        "skills": [
          "Java",
          "C#",
          "React"
        ]
      }
    ]
  }
}        

Working with parameters

As we can see that we have a working console application but what if there is a requirement to get just one record from the database. To make this work we need the following changes:

  1. Update he schema to support query with parameters.
  2. Create a method in Query class that can parse the parameter.
  3. Verify that the console app works.

Update the schema

We need to update the schema as shown below so that it takes name as an argument and return only those Employee whose name matches in the given argument.

 var schema = Schema.For(@" 
        type Employee{
            name: String,
            age: Int,
            salary: Float,
            isMarried: Boolean,
            designation: String,
            address: String,
            email: String,
            phone: String,
            skills: [String]
        }
         type Query{
            employees:[Employee]
            employee(name:String):Employee
        }
        
        ", _ =>
        {
            _.Types.Include<Query>();

        });        

We are adding name as parameter to the Query and returning just single record of Employee.

Updating the Query class

We will now add a method called GetEmployee(string name) to the Query class that will make a call to the CompanyDB (in memory database). The code will change as shown below:

[GraphQLMetadata("employee")]
    public Employee? GetEmployee(string name)
    {
        return CompanyDB.GetEmployee(name);
    }        

Updating the database

We will now add a method in CompanyDB to return single record that matches the provided employee name as shown below:

public static Employee? GetEmployee(string name)
    {
        return GetEmployees().FirstOrDefault(employee => employee.Name == name);
    }        

You also need to update the execution of Query in Program.cs file as shown below:

        var json = await schema.ExecuteAsync(_ =>
        {
            _.Query = "{employee(name:\"Luke\"){name,age,skills}}";

        });        

Verify application works

Rebuild the application and run it. The below will be shown as an output:

{
  "data": {
    "employee": {
      "name": "Luke",
      "age": 30,
      "skills": [
        "Python",
        "C",
        "ML"
      ]
    }
  }
}        

Summary

In this post we have introduced GQL (Graph Query Language). We have also learned how to define resources in our schema, custom types and resolving them. We have also created a sample application to see some concept in action.

Resources

The demo application is available here.


要查看或添加评论,请登录

社区洞察

其他会员也浏览了