First experience with graphQL
Tags: dotnet, csharp, learning, graphql
Published: 2024-06-27 10:14:58

As developers, we're constantly seeking efficient and flexible ways to manage data and interactions in our applications. For many years, RESTful APIs have been the standard for handling these interactions. However, a new contender has emerged in recent years, promising more flexibility and efficiency: GraphQL.

## What is GraphQL?

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

#### Key Features of GraphQL:

- **Declarative Data Fetching**: Clients can request exactly the data they need, and nothing more.

- **Single Endpoint**: All interactions are routed through a single endpoint, simplifying network architecture.

- **Strongly Typed Schema**: The API's schema is defined using types, ensuring clients know exactly what data is available and how it can be used.


## Setting Up GraphQL with .NET
To give you a practical taste, let's set up a simple GraphQL API.

#### Step 1: Install Required Packages
First, install the necessary NuGet packages:

- GraphQL
- GraphQL.Server.Transports.AspNetCore
- GraphQL.Server.Ui.GraphiQL

#### Step 2: Define Your Data Models
Create your data models. For instance, let's define Author and Book models:

```
public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Book> Books { get; set; }
}

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int AuthorId { get; set; }
    public Author Author { get; set; }
}

```

#### Step 3: Create Your DbContext
Define your LibraryContext:

```
public class LibraryContext : DbContext
{
    public LibraryContext(DbContextOptions<LibraryContext> options) : base(options) { }

    public DbSet<Book> Books { get; set; }
    public DbSet<Author> Authors { get; set; }
}
```

#### Step 4: Setup your repository
Create your repository class:

```
public interface ILibraryRepository
{
    IEnumerable<Book> GetBooks();
    Book GetBookById(int id);
    Book AddBook(string title, int authorId);
    IEnumerable<Author> GetAuthors();

    Author GetAuthorById(int id);

    Author AddAuthor(Author author);
}

public class LibraryRepository : ILibraryRepository
{
    private readonly LibraryContext _context;

    public LibraryRepository(LibraryContext context)
    {
        _context = context;
    }

    public IEnumerable<Book> GetBooks() => _context.Books.Include(b => b.Author).ToList();

    public Book GetBookById(int id) => _context.Books.Include(b => b.Author).FirstOrDefault(b => b.Id == id);

    public Book AddBook(string title, int authorId)
    {
        var book = new Book { Title = title, AuthorId = authorId };
        _context.Books.Add(book);
        _context.SaveChanges();
        return book;
    }

    public IEnumerable<Author> GetAuthors() => _context.Authors.Include(a => a.Books).ToList();

    public Author GetAuthorById(int id) => _context.Authors.Include(a => a.Books).FirstOrDefault(b => b.Id == id);

    public Author AddAuthor(Author author)
    {
        _context.Authors.Add(author);
        _context.SaveChanges();
        return author;
    }
}
```

#### Step 5: Set Up GraphQL Types
Create GraphQL types:

```
public class AuthorType : ObjectGraphType<Author>
{
    public AuthorType()
    {
        Field(x => x.Id);
        Field(x => x.Name);
        Field<ListGraphType<BookType>>("books", resolve: context => context.Source.Books);
    }
}


public class BookType : ObjectGraphType<Book>
{
    public BookType()
    {
        Field(x => x.Id);
        Field(x => x.Title);
        Field<AuthorType>("author", resolve: context => context.Source.Author);
    }
}

```

#### Step 6: Define Queries and Mutations

```
public class LibraryQuery : ObjectGraphType
{
    public LibraryQuery(ILibraryRepository repository)
    {
        Field<ListGraphType<BookType>>(
            "books",
            resolve: context => repository.GetBooks());

        Field<BookType>(
            "book",
            arguments: new QueryArguments(new QueryArgument<IntGraphType> { Name = "id" }),
            resolve: context => repository.GetBookById(context.GetArgument<int>("id")));

        Field<ListGraphType<AuthorType>>(
            "authors",
            resolve: context => repository.GetAuthors());

        Field<AuthorType>(
            "author",
            arguments: new QueryArguments(new QueryArgument<IntGraphType> { Name = "id" }),
            resolve: context => repository.GetAuthorById(context.GetArgument<int>("id")));
    }
}

public class LibraryMutation : ObjectGraphType
{
    public LibraryMutation(ILibraryRepository repository)
    {
        Field<BookType>(
            "addBook",
            arguments: new QueryArguments(
                new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "title" },
                new QueryArgument<NonNullGraphType<IntGraphType>> { Name = "authorId" }),
            resolve: context =>
            {
                var title = context.GetArgument<string>("title");
                var authorId = context.GetArgument<int>("authorId");
                return repository.AddBook(title, authorId);
            });

        Field<AuthorType>(
            "addAuthor",
            arguments: new QueryArguments(
                new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "name" }),
            resolve: context =>
            {
                var name = context.GetArgument<string>("name");
                var author = new Author
                {
                    Name = name,
                    Books = new List<Book>() // Initialize books list as needed
                };
                return repository.AddAuthor(author);
            });
    }
}
```

#### Step 7: Define Schema

```
public class LibrarySchema : Schema
{
    public LibrarySchema(IServiceProvider provider) : base(provider)
    {
        Query = provider.GetRequiredService<LibraryQuery>();
        Mutation = provider.GetRequiredService<LibraryMutation>();
    }
}
```

#### Step 8: Configure program.cs

In your program.cs file add the following:

```
var connectionString = builder.Configuration.GetConnectionString("LibraryContext");
builder.Services.AddDbContext<LibraryContext>(options =>
        options.UseSqlServer(connectionString));

builder.Services.AddScoped<ILibraryRepository, LibraryRepository>();

builder.Services.AddScoped<BookType>();
builder.Services.AddScoped<AuthorType>();
builder.Services.AddScoped<LibraryQuery>();
builder.Services.AddScoped<LibraryMutation>();
builder.Services.AddScoped<ISchema, LibrarySchema>();

builder.Services.AddGraphQL(b => b.AddSystemTextJson());

pp.UseGraphQL<ISchema>();
app.UseGraphQLGraphiQL();
```

#### Step 9: Test API

To test the graphQL API, I used GraphiQL. You must run your api and append '/ui/graphiql' to the API url to launch the playground.

An example of a mutation:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8pv78nid49y0mnddjt5.png)


An example of a query:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9k3tx8zvtrnf1fhgzd64.png)




And that's it guys, a simple use of graphQL, I hope you liked it, stay tuned for more!