Hello Everyone
Today, we will delve into one of the modern API architectures.
GraphQL
GraphQL, developed by Facebook, is a modern API architecture that allows clients to request precisely the data they need. Unlike traditional REST APIs, GraphQL provides flexibility and efficiency in fetching data by enabling clients to query multiple resources in a single request.
GraphQL is a powerful query language for APIs, enabling clients to request exactly the data they need. With .NET 8 and the HotChocolate library, building a robust GraphQL API is straightforward. In this article, we’ll create a GraphQL API to manage a collection of books using a book repository.
Prerequisites
Before diving in, ensure you have,
- .NET 8 SDK installed.
- Basic knowledge of C# and GraphQL.
Step 1. Setting Up the Project.
- Create a new .NET 8 Web API project12dotnet new web <span class="token parameter variable">-n</span> GraphQLApi<span class="token builtin class-name">cd</span> GraphQLApi
- Add the HotChocolate NuGet packages12dotnet <span class="token function">add</span> package HotChocolate.AspNetCoredotnet <span class="token function">add</span> package HotChocolate.Data
Step 2. Defining the Data Model.
Create a Book
class to represent the data.
1 2 3 4 5 6 7 8 9 | <span class="token keyword keyword-namespace">namespace</span> <span class="token namespace">GraphQLApi</span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">Book</span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-int">int</span></span> Id <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-string">string</span></span> Title <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-string">string</span></span> Author <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Step 3. Implementing the Repository.
The BookRepository handles CRUD operations. Here’s the implementation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <span class="token keyword keyword-namespace">namespace</span> <span class="token namespace">GraphQLApi</span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">BookRepository</span> <span class="token punctuation">{</span> <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">List<span class="token punctuation"><</span>Book<span class="token punctuation">></span></span> _books <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Book</span> <span class="token punctuation">{</span> Id <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">,</span> Title <span class="token operator">=</span> <span class="token string">"C# in Depth"</span><span class="token punctuation">,</span> Author <span class="token operator">=</span> <span class="token string">"Jon Skeet"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Book</span> <span class="token punctuation">{</span> Id <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">,</span> Title <span class="token operator">=</span> <span class="token string">"Clean Code"</span><span class="token punctuation">,</span> Author <span class="token operator">=</span> <span class="token string">"Robert C. Martin"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">IQueryable<span class="token punctuation"><</span>Book<span class="token punctuation">></span></span> <span class="token function">GetBooks</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> _books<span class="token punctuation">.</span><span class="token function">AsQueryable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">Book</span> <span class="token function">GetBook</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-int">int</span></span> id<span class="token punctuation">)</span> <span class="token operator">=></span> _books<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>Id <span class="token operator">==</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">Book</span> <span class="token function">AddBook</span><span class="token punctuation">(</span><span class="token class-name">Book</span> book<span class="token punctuation">)</span> <span class="token punctuation">{</span> book<span class="token punctuation">.</span>Id <span class="token operator">=</span> _books<span class="token punctuation">.</span><span class="token function">Max</span><span class="token punctuation">(</span>b <span class="token operator">=></span> b<span class="token punctuation">.</span>Id<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> _books<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>book<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> book<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">Book</span> <span class="token function">UpdateBook</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-int">int</span></span> id<span class="token punctuation">,</span> <span class="token class-name">Book</span> book<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> bookDetail <span class="token operator">=</span> <span class="token function">GetBook</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>bookDetail <span class="token operator">!=</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> _books<span class="token punctuation">.</span><span class="token function">Remove</span><span class="token punctuation">(</span>bookDetail<span class="token punctuation">)</span><span class="token punctuation">;</span> book<span class="token punctuation">.</span>Id <span class="token operator">=</span> bookDetail<span class="token punctuation">.</span>Id<span class="token punctuation">;</span> _books<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>book<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> book<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-bool">bool</span></span> <span class="token function">DeleteBook</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-int">int</span></span> id<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> bookDetail <span class="token operator">=</span> <span class="token function">GetBook</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>bookDetail <span class="token operator">!=</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> _books<span class="token punctuation">.</span><span class="token function">Remove</span><span class="token punctuation">(</span>bookDetail<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-return">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Step 4. Defining the GraphQL Schema.
Query Type
The Query
class defines methods to fetch data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword keyword-using">using</span> <span class="token namespace">GraphQLApi<span class="token punctuation">.</span>Models</span><span class="token punctuation">;</span> <span class="token keyword keyword-using">using</span> <span class="token namespace">GraphQLApi<span class="token punctuation">.</span>Repositories</span><span class="token punctuation">;</span> <span class="token keyword keyword-namespace">namespace</span> <span class="token namespace">GraphQLApi<span class="token punctuation">.</span>GraphQL</span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">Query</span> <span class="token punctuation">{</span> <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">BookRepository</span> _repository<span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token function">Query</span><span class="token punctuation">(</span><span class="token class-name">BookRepository</span> repository<span class="token punctuation">)</span> <span class="token punctuation">{</span> _repository <span class="token operator">=</span> repository<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">IQueryable<span class="token punctuation"><</span>Book<span class="token punctuation">></span></span> <span class="token function">GetBooks</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> _repository<span class="token punctuation">.</span><span class="token function">GetBooks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">Book</span> <span class="token function">GetBook</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-int">int</span></span> id<span class="token punctuation">)</span> <span class="token operator">=></span> _repository<span class="token punctuation">.</span><span class="token function">GetBook</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Mutation Type
The Mutation class defines methods for modifying data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <span class="token keyword keyword-namespace">namespace</span> <span class="token namespace">GraphQLApi</span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">Mutation</span> <span class="token punctuation">{</span> <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">BookRepository</span> _repository<span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token function">Mutation</span><span class="token punctuation">(</span><span class="token class-name">BookRepository</span> repository<span class="token punctuation">)</span> <span class="token punctuation">{</span> _repository <span class="token operator">=</span> repository<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">Book</span> <span class="token function">AddBook</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-string">string</span></span> title<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword keyword-string">string</span></span> author<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> book <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Book</span> <span class="token punctuation">{</span> Title <span class="token operator">=</span> title<span class="token punctuation">,</span> Author <span class="token operator">=</span> author <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> _repository<span class="token punctuation">.</span><span class="token function">AddBook</span><span class="token punctuation">(</span>book<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">Book</span> <span class="token function">UpdateBook</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-int">int</span></span> id<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword keyword-string">string</span></span> title<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword keyword-string">string</span></span> author<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> book <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Book</span> <span class="token punctuation">{</span> Id <span class="token operator">=</span> id<span class="token punctuation">,</span> Title <span class="token operator">=</span> title<span class="token punctuation">,</span> Author <span class="token operator">=</span> author <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> _repository<span class="token punctuation">.</span><span class="token function">UpdateBook</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> book<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-bool">bool</span></span> <span class="token function">DeleteBook</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-int">int</span></span> id<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-return">return</span> _repository<span class="token punctuation">.</span><span class="token function">DeleteBook</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Step 5. Configuring the GraphQL Server.
Update the Program.cs file to configure the GraphQL server.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <span class="token keyword keyword-using">using</span> <span class="token namespace">GraphQLApi</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> builder <span class="token operator">=</span> WebApplication<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Add services to the container.</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token function">AddEndpointsApiExplorer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token function">AddSwaggerGen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Add services</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation"><</span>BookRepository<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Add GraphQL service support</span> builder<span class="token punctuation">.</span>Services <span class="token punctuation">.</span><span class="token function">AddGraphQLServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddQueryType</span><span class="token generic class-name"><span class="token punctuation"><</span>Query<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddMutationType</span><span class="token generic class-name"><span class="token punctuation"><</span>Mutation<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AddFiltering</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AddSorting</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> app <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Configure the HTTP request pipeline.</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>app<span class="token punctuation">.</span>Environment<span class="token punctuation">.</span><span class="token function">IsDevelopment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> app<span class="token punctuation">.</span><span class="token function">UseSwagger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">UseSwaggerUI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> app<span class="token punctuation">.</span><span class="token function">UseHttpsRedirection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Configure the HTTP request pipeline</span> app<span class="token punctuation">.</span><span class="token function">MapGraphQL</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Step 6. Running and Testing the API.
Run the application.
1 | dotnet run |
Open the GraphQL Playground in your browser at http://localhost:5000/graphql.
Example Queries and Mutations
Query All Books
1 2 3 4 5 6 7 | <span class="token keyword keyword-query">query</span> <span class="token punctuation">{</span> <span class="token object">books</span> <span class="token punctuation">{</span> <span class="token property">id</span> <span class="token property">title</span> <span class="token property">author</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Query a Single Book
1 2 3 4 5 6 7 | <span class="token keyword keyword-query">query</span> <span class="token punctuation">{</span> <span class="token property-query">bookById</span><span class="token punctuation">(</span><span class="token attr-name">id</span><span class="token punctuation">:</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">id</span> <span class="token property">title</span> <span class="token property">author</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Add a New Book
1 2 3 4 5 6 7 | <span class="token keyword keyword-mutation">mutation</span> <span class="token punctuation">{</span> <span class="token property-query property-mutation">addBook</span><span class="token punctuation">(</span> <span class="token attr-name">title</span><span class="token punctuation">:</span> <span class="token string">"New Book"</span><span class="token punctuation">,</span> <span class="token attr-name">author</span><span class="token punctuation">:</span> <span class="token string">"Author Name"</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token property">id</span> <span class="token property">title</span> <span class="token property">author</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Update an Existing Book
1 2 3 4 5 6 7 | mutation <span class="token punctuation">{</span> <span class="token function">updateBook</span><span class="token punctuation">(</span><span class="token named-parameter punctuation">id</span><span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">title</span><span class="token punctuation">:</span> <span class="token string">"Updated Title"</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">author</span><span class="token punctuation">:</span> <span class="token string">"Updated Author"</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> id title author <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Delete a Book
1 2 3 | <span class="token keyword keyword-mutation">mutation</span> <span class="token punctuation">{</span> <span class="token property-query property-mutation">deleteBook</span><span class="token punctuation">(</span><span class="token attr-name">id</span><span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Sample ScreenShot
GraphQL vs REST Comparision
Aspect | GraphQL | REST |
---|---|---|
Endpoint | Single endpoint for all operations. | Multiple endpoints for different resources. |
Data Fetching | Fetches only required fields in one query. | Returns fixed data structures, often over-fetching or under-fetching. |
Flexibility | Highly flexible; client defines the response. | The server defines a response structure that is less flexible. |
Performance | Combines multiple queries into one request. | Requires multiple requests for related resources. |
Versioning | No versioning is needed; it evolves with schema changes. | Requires versioning for major updates (e.g., /v1, /v2). |
Real-Time | Built-in support for subscriptions (real-time). | Limited real-time capabilities; needs additional setup. |
Use Cases | Best for complex, dynamic, or real-time needs. | Ideal for simpler, well-defined APIs. |
Conclusion
With .NET 8 and HotChocolate, creating a GraphQL API is simple and efficient. This example demonstrates the core concepts of building and managing an API with queries and mutations. You can extend this implementation by adding advanced features like authorization and subscriptions or integrating with a database. For more details, check out this documentation link GraphQL
Happy coding!
ASP.NET 8.0.11 Hosting Recommendation
ASP.NET is a powerful platform for creating web applications and services. You must be comfortable with JavaScript, HTML, CSS, and C# before developing a web application in ASP.NET. On the market, there are thousands of web hosting companies providing ASP.NET Hosting. But, only very few web hosting companies could provide high quality ASP.NET hosting solution.
ASP.NET is the best development language in Windows platform, which is released by Microsoft and widely used to build all types of dynamic Web sites and XML Web services. With this article, we’re going to help you to find the best ASP.NET Hosting solution in Europe based on reliability, features, price, performance and technical support. After we reviewed about 30+ ASP.NET hosting providers in Europe, our Best ASP.NET Hosting Award in Europe goes to HostForLIFE.eu, one of the fastest growing private companies and one of the most reliable hosting providers in Europe.