First experience with graphQL

vzldev

VzlDev

Posted on June 27, 2024

First experience with graphQL

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; }
}

Enter fullscreen mode Exit fullscreen mode

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; }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}

Enter fullscreen mode Exit fullscreen mode

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);
            });
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Define Schema

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

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();
Enter fullscreen mode Exit fullscreen mode

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

An example of a query:

Image description

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

💖 💪 🙅 🚩
vzldev
VzlDev

Posted on June 27, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

First experience with graphQL
dotnet First experience with graphQL

June 27, 2024