{"id":1569,"date":"2023-10-07T02:44:11","date_gmt":"2023-10-07T02:44:11","guid":{"rendered":"https:\/\/www.w3computing.com\/articles\/?p=1569"},"modified":"2023-10-07T02:44:13","modified_gmt":"2023-10-07T02:44:13","slug":"building-crud-api-with-csharp-graphql","status":"publish","type":"post","link":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/","title":{"rendered":"Building a CRUD API with C# and GraphQL"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is GraphQL?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data. Unlike other API standards that focus on defining fixed endpoints, GraphQL enables clients to request exactly the data they need, and no more. Developed by Facebook in 2012 and released as an open-source project in 2015, GraphQL provides a more efficient, flexible, and powerful alternative to the traditional REST API.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At its core, GraphQL allows for declarative data fetching where a client can specify exactly what data it needs. Instead of multiple endpoints that return fixed sets of data, a GraphQL server exposes a single endpoint and responds with precisely the data a client asked for.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Advantages of GraphQL over REST<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Flexibility for Clients<\/strong>: GraphQL empowers clients to shape the responses according to their needs. This means that applications can fetch the exact data they need, without over-fetching or under-fetching of data. This can be especially beneficial for mobile devices or slow network situations where minimizing the amount and size of the data is crucial.<\/li>\n\n\n\n<li><strong>Single Endpoint<\/strong>: Unlike REST where the design is based around having multiple endpoints for different resources, GraphQL typically exposes a single endpoint. This simplifies the process, reduces the number of requests, and makes versioning more straightforward.<\/li>\n\n\n\n<li><strong>Strongly Typed Schema<\/strong>: With GraphQL, the schema is strongly typed, meaning every data point has a specific type associated with it. This enables introspection, allowing clients to discover capabilities of the schema via the API itself. It also ensures that the data is consistent and adheres to a predetermined structure.<\/li>\n\n\n\n<li><strong>Reduction in Overhead<\/strong>: By allowing clients to request only the data they need, there&#8217;s a significant reduction in the amount of data transferred over the network, which can improve application performance, especially on slower connections.<\/li>\n\n\n\n<li><strong>Built-in Documentation<\/strong>: Thanks to its strongly-typed nature and introspection capabilities, GraphQL APIs can be auto-documented. Tools like GraphQL Playground provide interactive documentation for developers, reducing the effort required to keep documentation up-to-date.<\/li>\n\n\n\n<li><strong>Avoid Over-fetching and Under-fetching<\/strong>: One of the primary challenges with REST is the potential to over-fetch or under-fetch data. With GraphQL, the client specifies the required data, ensuring they get exactly what they need without unnecessary additional information or missing any crucial data points.<\/li>\n\n\n\n<li><strong>Easier Versioning<\/strong>: In REST, changes often require a new version of the endpoint, leading to versioning challenges. In GraphQL, new fields can be added to the schema without impacting existing queries, making versioning simpler and more intuitive.<\/li>\n\n\n\n<li><strong>Batching &amp; Caching<\/strong>: Tools like DataLoader can be integrated with GraphQL to batch multiple requests into a single request, and cache requests to optimize performance.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">While REST has its own set of advantages and is still widely used, GraphQL offers a more dynamic and flexible approach to designing and consuming APIs. Its focus on allowing clients to define their data requirements makes it particularly well-suited for today&#8217;s varied and rapidly evolving application needs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding the Basics of GraphQL<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To fully harness the capabilities of GraphQL when building our API with C#, it&#8217;s crucial to grasp some of its foundational concepts. Let&#8217;s delve into the basics of GraphQL and understand its main components.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">GraphQL Schema<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At the heart of any GraphQL API is its schema. The schema defines the types of data you can query and the set of possible operations you can perform. It serves as a contract between the client and the server, describing the shape of the response the client can expect.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In essence, the schema outlines:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>What<\/strong> can be queried (Queries).<\/li>\n\n\n\n<li><strong>How<\/strong> data can be changed (Mutations).<\/li>\n\n\n\n<li>The <strong>shape and structure<\/strong> of the data objects (Types).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Types<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GraphQL is a strongly typed language, and as such, the schema defines specific types that represent the shape of the data you can fetch.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Scalar Types<\/strong>: These are the primitives like <code>Int<\/code>, <code>Float<\/code>, <code>String<\/code>, <code>Boolean<\/code>, and <code>ID<\/code>. While these are the default scalar types, you can also define custom scalars for your API if needed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Object Types<\/strong>: These represent the kind of objects you can fetch from your service and the fields they contain. For instance, consider a <code>Book<\/code> type:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">type<\/span> <span class=\"hljs-selector-tag\">Book<\/span> {\n  <span class=\"hljs-attribute\">id<\/span>: ID!\n  title: String!\n  author: String!\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The <code>!<\/code> denotes that the field is non-nullable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Enum Types<\/strong>: Enums are a special kind of scalar restricted to a particular set of allowed values. They&#8217;re useful when an object can be in one of a small set of possible states.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Queries<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Queries allow clients to request specific data as per their needs. They represent the &#8220;R&#8221; in &#8220;CRUD&#8221; (i.e., read operations). A client specifies what set of data it needs, and the server responds with the matching data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, a simple query to fetch a book by its ID might look like:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\"><span><code class=\"hljs\">query {\n  book(id: 1) {\n    title\n    author\n  }\n}<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Mutations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">While queries are all about fetching data, mutations are about modifying data. They represent the &#8220;C&#8221;, &#8220;U&#8221;, and &#8220;D&#8221; in &#8220;CRUD&#8221; (i.e., create, update, delete operations).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A mutation to add a new book might be structured as:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">mutation {\n  addBook(title: <span class=\"hljs-string\">\"New Book\"<\/span>, <span class=\"hljs-attr\">author<\/span>: <span class=\"hljs-string\">\"John Doe\"<\/span>) {\n    id\n    title\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Resolvers and their role<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Resolvers are functions that handle the process of fetching the data for a particular field in your schema. Every field in a GraphQL schema is backed by a resolver. When a client sends a query or mutation to the server, the GraphQL server invokes the resolver for each field in the received request.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The role of a resolver is twofold:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Data Retrieval<\/strong>: It retrieves the requested data from the source, be it a database, another API, or any other data source.<\/li>\n\n\n\n<li><strong>Data Transformation<\/strong>: Resolvers can also transform the data before sending it back to the client, ensuring it matches the shape defined in the schema.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">In essence, resolvers are the bridge between a GraphQL query and the actual backend logic that retrieves or modifies the data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up GraphQL in C#<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To integrate GraphQL into our C# project, we need to leverage specific libraries that facilitate this integration. One of the most popular libraries for this purpose in the .NET ecosystem is HotChocolate. Alongside, to manage our database interactions, we&#8217;ll use Entity Framework Core. Let&#8217;s walk through the steps to set everything up.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installing required NuGet packages<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>HotChocolate<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">HotChocolate is a GraphQL server for .NET. It provides all the essential tooling to set up a GraphQL endpoint with ease.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using .NET CLI:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">dotnet add package HotChocolate.AspNetCore\ndotnet add package HotChocolate.AspNetCore.Playground<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Using Visual Studio:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Open the &#8220;NuGet Package Manager&#8221; or &#8220;Manage NuGet Packages for Solution&#8221;.<\/li>\n\n\n\n<li>Search for &#8220;HotChocolate.AspNetCore&#8221; and install it.<\/li>\n\n\n\n<li>Similarly, search for &#8220;HotChocolate.AspNetCore.Playground&#8221; and install it.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Entity Framework Core<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Entity Framework (EF) Core is an ORM (Object-Relational Mapper) that simplifies database operations in .NET applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using .NET CLI (assuming SQL Server as the database, adjust accordingly if using another database provider):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">dotnet add package Microsoft.EntityFrameworkCore\ndotnet add package Microsoft.EntityFrameworkCore.SqlServer<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Using Visual Studio:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Open the &#8220;NuGet Package Manager&#8221;.<\/li>\n\n\n\n<li>Search for &#8220;Microsoft.EntityFrameworkCore&#8221; and install it.<\/li>\n\n\n\n<li>Similarly, search for &#8220;Microsoft.EntityFrameworkCore.SqlServer&#8221; and install it.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Integrating GraphQL middleware with ASP.NET Core<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Update Startup.cs<\/strong>:After installing the necessary packages, we need to configure our application to use HotChocolate and set up a GraphQL endpoint.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In <code>Startup.cs<\/code>, add the following using directives:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\n<span class=\"hljs-keyword\">using<\/span> HotChocolate.AspNetCore;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In the <code>ConfigureServices<\/code> method, register the GraphQL services:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">ConfigureServices<\/span>(<span class=\"hljs-params\">IServiceCollection services<\/span>)<\/span>\n{\n    services.AddDbContext&lt;YourDbContextClass&gt;(options =&gt; \n        options.UseSqlServer(Configuration.GetConnectionString(<span class=\"hljs-string\">\"YourConnectionStringName\"<\/span>)));\n\n    services.AddGraphQL(sp =&gt; \n        SchemaBuilder.New()\n        .AddQueryType&lt;YourQueryTypeClass&gt;()\n        .AddMutationType&lt;YourMutationTypeClass&gt;()\n        .Create());\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In the <code>Configure<\/code> method, integrate the GraphQL middleware and optionally the Playground (a GraphQL IDE) for testing:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IApplicationBuilder app, IWebHostEnvironment env<\/span>)<\/span>\n{\n    <span class=\"hljs-comment\">\/\/ ... other middleware ...<\/span>\n\n    app.UseRouting();\n\n    app.UseEndpoints(endpoints =&gt;\n    {\n        endpoints.MapGraphQL();\n    });\n\n    <span class=\"hljs-comment\">\/\/ If you want to use the GraphQL Playground for testing:<\/span>\n    app.UsePlayground();\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Define the DbContext and Models<\/strong>:At this point, you&#8217;d typically define your Entity Framework DbContext and related models, which would then be used to shape your GraphQL schema. Ensure that your DbContext is properly set up to interact with your database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>GraphQL Types, Queries, and Mutations<\/strong>:We briefly touched upon these in the previous section. You&#8217;ll now use C# classes to define these structures in conjunction with HotChocolate. For instance, if you have a <code>Book<\/code> model, you might create a <code>BookType<\/code> class to represent it in GraphQL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With these configurations in place, you&#8217;re all set to start defining your GraphQL schema, types, and resolvers using C# and HotChocolate. As you proceed, you&#8217;ll find that HotChocolate offers a wide range of features, making it an excellent choice for building sophisticated GraphQL APIs in .NET.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Designing the Data Model<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The backbone of any database-driven application lies in its data model, which represents the structured data, relationships, and rules. When working with GraphQL and Entity Framework, it&#8217;s pivotal to have a clear understanding of the entities and their relationships, as this directly impacts the GraphQL schema and the queries\/mutations you will define.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Entities and their relationships<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Book<\/strong>:Represents a book with basic details.\n<ul class=\"wp-block-list\">\n<li>Properties: <code>Id<\/code>, <code>Title<\/code>, <code>ISBN<\/code>, <code>PublicationDate<\/code>, <code>AuthorId<\/code>, <code>PublisherId<\/code><\/li>\n\n\n\n<li>Relationships:\n<ul class=\"wp-block-list\">\n<li>Many-to-One with <code>Author<\/code>: A book has one author, but an author can write many books.<\/li>\n\n\n\n<li>Many-to-One with <code>Publisher<\/code>: A book has one publisher, but a publisher can publish many books.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Author<\/strong>:Represents an author who writes books.\n<ul class=\"wp-block-list\">\n<li>Properties: <code>Id<\/code>, <code>Name<\/code>, <code>DateOfBirth<\/code>, <code>Biography<\/code><\/li>\n\n\n\n<li>Relationships:\n<ul class=\"wp-block-list\">\n<li>One-to-Many with <code>Book<\/code>: An author can write many books, but a book is written by one author.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Publisher<\/strong>:Represents a publishing entity.\n<ul class=\"wp-block-list\">\n<li>Properties: <code>Id<\/code>, <code>Name<\/code>, <code>EstablishedDate<\/code>, <code>Address<\/code><\/li>\n\n\n\n<li>Relationships:\n<ul class=\"wp-block-list\">\n<li>One-to-Many with <code>Book<\/code>: A publisher can publish many books, but a book is published by one publisher.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Setting up the Entity Framework context<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Define the Entity Models<\/strong>:First, create a <code>Models<\/code> folder in your project. Inside, define the entities:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ Book.cs<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Book<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> Id { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Title { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> ISBN { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> DateTime PublicationDate { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> Author Author { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> AuthorId { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> Publisher Publisher { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> PublisherId { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n\n<span class=\"hljs-comment\">\/\/ Author.cs<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Author<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> Id { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Name { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> DateTime DateOfBirth { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Biography { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> ICollection&lt;Book&gt; Books { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n\n<span class=\"hljs-comment\">\/\/ Publisher.cs<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Publisher<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> Id { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Name { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> DateTime EstablishedDate { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Address { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> ICollection&lt;Book&gt; Books { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Setup the DbContext<\/strong>:In the root of your project or inside a <code>Data<\/code> folder, create a new class for your DbContext:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> Microsoft.EntityFrameworkCore;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AppDbContext<\/span> : <span class=\"hljs-title\">DbContext<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">AppDbContext<\/span>(<span class=\"hljs-params\">DbContextOptions&lt;AppDbContext&gt; options<\/span>) : <span class=\"hljs-title\">base<\/span>(<span class=\"hljs-params\">options<\/span>)<\/span> { }\n\n    <span class=\"hljs-keyword\">public<\/span> DbSet&lt;Book&gt; Books { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> DbSet&lt;Author&gt; Authors { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    <span class=\"hljs-keyword\">public<\/span> DbSet&lt;Publisher&gt; Publishers { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">OnModelCreating<\/span>(<span class=\"hljs-params\">ModelBuilder modelBuilder<\/span>)<\/span>\n    {\n        <span class=\"hljs-comment\">\/\/ Define relationships and any other model configurations here<\/span>\n        modelBuilder.Entity&lt;Book&gt;()\n            .HasOne(b =&gt; b.Author)\n            .WithMany(a =&gt; a.Books)\n            .HasForeignKey(b =&gt; b.AuthorId);\n\n        modelBuilder.Entity&lt;Book&gt;()\n            .HasOne(b =&gt; b.Publisher)\n            .WithMany(p =&gt; p.Books)\n            .HasForeignKey(b =&gt; b.PublisherId);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Configure DbContext in Startup.cs<\/strong>:Remember to register the <code>AppDbContext<\/code> in the <code>ConfigureServices<\/code> method:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddDbContext&lt;AppDbContext&gt;(options =&gt; \n    options.UseSqlServer(Configuration.GetConnectionString(<span class=\"hljs-string\">\"YourConnectionStringName\"<\/span>)));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">With the data model designed and the Entity Framework context set up, we&#8217;re now prepared to dive into GraphQL specifics, linking our data model to GraphQL types, queries, and mutations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Creating the GraphQL Schema<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">With our data model ready, the next step is to represent these entities in our GraphQL schema. In HotChocolate, we create classes that represent GraphQL object types for each of our data entities.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Defining Types<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>BookType<\/strong>:This will represent our <code>Book<\/code> entity in the GraphQL schema.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate.Types;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Models;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookType<\/span> : <span class=\"hljs-title\">ObjectType<\/span>&lt;<span class=\"hljs-title\">Book<\/span>&gt;\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IObjectTypeDescriptor&lt;Book&gt; descriptor<\/span>)<\/span>\n    {\n        descriptor.Description(<span class=\"hljs-string\">\"Represents any book available in the store.\"<\/span>);\n\n        descriptor\n            .Field(b =&gt; b.Id)\n            .Description(<span class=\"hljs-string\">\"Represents the unique ID for the book.\"<\/span>);\n\n        descriptor\n            .Field(b =&gt; b.ISBN)\n            .Description(<span class=\"hljs-string\">\"Represents the unique ISBN number of the book.\"<\/span>);\n\n        descriptor\n            .Field(b =&gt; b.Author)\n            .ResolveWith&lt;Resolvers&gt;(b =&gt; b.GetAuthor(<span class=\"hljs-keyword\">default<\/span>!, <span class=\"hljs-keyword\">default<\/span>!))\n            .UseDbContext&lt;AppDbContext&gt;()\n            .Description(<span class=\"hljs-string\">\"This is the author associated with the given book.\"<\/span>);\n\n        descriptor\n            .Field(b =&gt; b.Publisher)\n            .ResolveWith&lt;Resolvers&gt;(b =&gt; b.GetPublisher(<span class=\"hljs-keyword\">default<\/span>!, <span class=\"hljs-keyword\">default<\/span>!))\n            .UseDbContext&lt;AppDbContext&gt;()\n            .Description(<span class=\"hljs-string\">\"This is the publisher that published the given book.\"<\/span>);\n    }\n\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Resolvers<\/span>\n    {\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Author <span class=\"hljs-title\">GetAuthor<\/span>(<span class=\"hljs-params\">Book book, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">return<\/span> context.Authors.FirstOrDefault(a =&gt; a.Id == book.AuthorId);\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Publisher <span class=\"hljs-title\">GetPublisher<\/span>(<span class=\"hljs-params\">Book book, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">return<\/span> context.Publishers.FirstOrDefault(p =&gt; p.Id == book.PublisherId);\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>AuthorType<\/strong>:This will represent our <code>Author<\/code> entity in the GraphQL schema.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate.Types;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AuthorType<\/span> : <span class=\"hljs-title\">ObjectType<\/span>&lt;<span class=\"hljs-title\">Author<\/span>&gt;\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IObjectTypeDescriptor&lt;Author&gt; descriptor<\/span>)<\/span>\n    {\n        descriptor.Description(<span class=\"hljs-string\">\"Represents the author of the book.\"<\/span>);\n\n        descriptor\n            .Field(a =&gt; a.Id)\n            .Description(<span class=\"hljs-string\">\"Represents the unique ID for the author.\"<\/span>);\n\n        descriptor\n            .Field(a =&gt; a.Books)\n            .ResolveWith&lt;Resolvers&gt;(a =&gt; a.GetBooks(<span class=\"hljs-keyword\">default<\/span>!, <span class=\"hljs-keyword\">default<\/span>!))\n            .UseDbContext&lt;AppDbContext&gt;()\n            .Description(<span class=\"hljs-string\">\"This is the list of books authored by the given author.\"<\/span>);\n    }\n\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Resolvers<\/span>\n    {\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IEnumerable&lt;Book&gt; <span class=\"hljs-title\">GetBooks<\/span>(<span class=\"hljs-params\">Author author, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">return<\/span> context.Books.Where(b =&gt; b.AuthorId == author.Id);\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>PublisherType<\/strong>:Representing our <code>Publisher<\/code> entity in the GraphQL schema.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate.Types;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">PublisherType<\/span> : <span class=\"hljs-title\">ObjectType<\/span>&lt;<span class=\"hljs-title\">Publisher<\/span>&gt;\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IObjectTypeDescriptor&lt;Publisher&gt; descriptor<\/span>)<\/span>\n    {\n        descriptor.Description(<span class=\"hljs-string\">\"Represents the publisher of the book.\"<\/span>);\n\n        descriptor\n            .Field(p =&gt; p.Id)\n            .Description(<span class=\"hljs-string\">\"Represents the unique ID for the publisher.\"<\/span>);\n\n        descriptor\n            .Field(p =&gt; p.Books)\n            .ResolveWith&lt;Resolvers&gt;(p =&gt; p.GetBooks(<span class=\"hljs-keyword\">default<\/span>!, <span class=\"hljs-keyword\">default<\/span>!))\n            .UseDbContext&lt;AppDbContext&gt;()\n            .Description(<span class=\"hljs-string\">\"This is the list of books published by the given publisher.\"<\/span>);\n    }\n\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Resolvers<\/span>\n    {\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IEnumerable&lt;Book&gt; <span class=\"hljs-title\">GetBooks<\/span>(<span class=\"hljs-params\">Publisher publisher, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">return<\/span> context.Books.Where(b =&gt; b.PublisherId == publisher.Id);\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The above types demonstrate how we can define GraphQL object types in HotChocolate and link them to our data model. The resolvers handle the logic of fetching related entities. The <code>UseDbContext&lt;AppDbContext&gt;()<\/code> method ensures that we have a scoped database context available for each resolver.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These GraphQL types will play a central role when we define our queries and mutations, shaping the data we can fetch or modify via our GraphQL API.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Defining Queries and Mutations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once our GraphQL types are set up, the next step is to define how we can interact with the data \u2014 both in terms of fetching (queries) and modifying (mutations). Let&#8217;s dive into creating these operations for our <code>Book<\/code>, <code>Author<\/code>, and <code>Publisher<\/code> entities.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Fetching data (Queries)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>BookQueries<\/strong>:Queries related to fetching book data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\n<span class=\"hljs-keyword\">using<\/span> HotChocolate.Data;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Models;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Data;\n\n&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Query\"<\/span>)<\/span>]\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookQueries<\/span>\n{\n    &#91;<span class=\"hljs-meta\">UseDbContext(typeof(AppDbContext))<\/span>]\n    &#91;<span class=\"hljs-meta\">UseFiltering<\/span>]\n    &#91;<span class=\"hljs-meta\">UseSorting<\/span>]\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IQueryable&lt;Book&gt; <span class=\"hljs-title\">GetBooks<\/span>(<span class=\"hljs-params\">&#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> context.Books;\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Book <span class=\"hljs-title\">GetBook<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> id, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> context.Books.FirstOrDefault(b =&gt; b.Id == id);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>AuthorQueries<\/strong>:Queries related to fetching author data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Query\"<\/span>)<\/span>]\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AuthorQueries<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Author <span class=\"hljs-title\">GetAuthor<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> id, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> context.Authors.FirstOrDefault(a =&gt; a.Id == id);\n    }\n\n    &#91;<span class=\"hljs-meta\">UseDbContext(typeof(AppDbContext))<\/span>]\n    &#91;<span class=\"hljs-meta\">UseFiltering<\/span>]\n    &#91;<span class=\"hljs-meta\">UseSorting<\/span>]\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IQueryable&lt;Author&gt; <span class=\"hljs-title\">GetAuthors<\/span>(<span class=\"hljs-params\">&#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> context.Authors;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>PublisherQueries<\/strong>:Queries related to fetching publisher data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Query\"<\/span>)<\/span>]\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">PublisherQueries<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Publisher <span class=\"hljs-title\">GetPublisher<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> id, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> context.Publishers.FirstOrDefault(p =&gt; p.Id == id);\n    }\n\n    &#91;<span class=\"hljs-meta\">UseDbContext(typeof(AppDbContext))<\/span>]\n    &#91;<span class=\"hljs-meta\">UseFiltering<\/span>]\n    &#91;<span class=\"hljs-meta\">UseSorting<\/span>]\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IQueryable&lt;Publisher&gt; <span class=\"hljs-title\">GetPublishers<\/span>(<span class=\"hljs-params\">&#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> context.Publishers;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Modifying data (Mutations)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>BookMutations<\/strong>:Mutations related to modifying book data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Models;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Data;\n\n&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Mutation\"<\/span>)<\/span>]\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookMutations<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Book <span class=\"hljs-title\">AddBook<\/span>(<span class=\"hljs-params\">Book book, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        context.Books.Add(book);\n        context.SaveChanges();\n        <span class=\"hljs-keyword\">return<\/span> book;\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Book <span class=\"hljs-title\">UpdateBook<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> id, Book book, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">var<\/span> existingBook = context.Books.Find(id);\n        <span class=\"hljs-keyword\">if<\/span> (existingBook == <span class=\"hljs-literal\">null<\/span>)\n            <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> Exception(<span class=\"hljs-string\">$\"Book with ID <span class=\"hljs-subst\">{id}<\/span> not found.\"<\/span>);\n\n        existingBook.Title = book.Title;\n        <span class=\"hljs-comment\">\/\/ ... other updates ...<\/span>\n\n        context.SaveChanges();\n        <span class=\"hljs-keyword\">return<\/span> existingBook;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>AuthorMutations<\/strong>:Mutations related to modifying author data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Mutation\"<\/span>)<\/span>]\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AuthorMutations<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Author <span class=\"hljs-title\">AddAuthor<\/span>(<span class=\"hljs-params\">Author author, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        context.Authors.Add(author);\n        context.SaveChanges();\n        <span class=\"hljs-keyword\">return<\/span> author;\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Author <span class=\"hljs-title\">UpdateAuthor<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> id, Author author, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">var<\/span> existingAuthor = context.Authors.Find(id);\n        <span class=\"hljs-keyword\">if<\/span> (existingAuthor == <span class=\"hljs-literal\">null<\/span>)\n            <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> Exception(<span class=\"hljs-string\">$\"Author with ID <span class=\"hljs-subst\">{id}<\/span> not found.\"<\/span>);\n\n        existingAuthor.Name = author.Name;\n        <span class=\"hljs-comment\">\/\/ ... other updates ...<\/span>\n\n        context.SaveChanges();\n        <span class=\"hljs-keyword\">return<\/span> existingAuthor;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>PublisherMutations<\/strong>:Mutations related to modifying publisher data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Mutation\"<\/span>)<\/span>]\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">PublisherMutations<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Publisher <span class=\"hljs-title\">AddPublisher<\/span>(<span class=\"hljs-params\">Publisher publisher, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        context.Publishers.Add(publisher);\n        context.SaveChanges();\n        <span class=\"hljs-keyword\">return<\/span> publisher;\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Publisher <span class=\"hljs-title\">UpdatePublisher<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> id, Publisher publisher, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">var<\/span> existingPublisher = context.Publishers.Find(id);\n        <span class=\"hljs-keyword\">if<\/span> (existingPublisher == <span class=\"hljs-literal\">null<\/span>)\n            <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> Exception(<span class=\"hljs-string\">$\"Publisher with ID <span class=\"hljs-subst\">{id}<\/span> not found.\"<\/span>);\n\n        existingPublisher.Name = publisher.Name;\n        <span class=\"hljs-comment\">\/\/ ... other updates ...<\/span>\n\n        context.SaveChanges();\n        <span class=\"hljs-keyword\">return<\/span> existingPublisher;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Implementing Resolvers<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In GraphQL, resolvers are functions that determine how data for a particular field is fetched. They are central to GraphQL&#8217;s flexibility, allowing you to specify complex operations per field if needed. While in many cases, the default resolver (fetching a property directly from the parent object) is enough, sometimes we need to customize how a field is resolved, especially when dealing with relationships or aggregated data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Fetching Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For our tutorial, let&#8217;s delve deeper into the process of fetching data by focusing on retrieving a list of books.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Resolver for getting a list of books:<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Resolvers in HotChocolate are typically methods inside our type classes. However, if we need to fetch related data or perform some operations, we can define a custom resolver.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s enhance our <code>BookType<\/code> from earlier by adding a resolver that fetches the list of books:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\n<span class=\"hljs-keyword\">using<\/span> HotChocolate.Types;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Data;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Models;\n<span class=\"hljs-keyword\">using<\/span> System.Linq;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookType<\/span> : <span class=\"hljs-title\">ObjectType<\/span>&lt;<span class=\"hljs-title\">Book<\/span>&gt;\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IObjectTypeDescriptor&lt;Book&gt; descriptor<\/span>)<\/span>\n    {\n        descriptor.Description(<span class=\"hljs-string\">\"Represents any book available in the store.\"<\/span>);\n\n        <span class=\"hljs-comment\">\/\/ ... other field definitions ...<\/span>\n\n        descriptor\n            .Field(b =&gt; b.Author)\n            .ResolveWith&lt;Resolvers&gt;(r =&gt; r.GetAuthor(<span class=\"hljs-keyword\">default<\/span>!, <span class=\"hljs-keyword\">default<\/span>!))\n            .UseDbContext&lt;AppDbContext&gt;()\n            .Description(<span class=\"hljs-string\">\"This is the author associated with the given book.\"<\/span>);\n    }\n\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Resolvers<\/span>\n    {\n        <span class=\"hljs-comment\">\/\/ This method is a resolver for the 'Author' field in the BookType.<\/span>\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Author <span class=\"hljs-title\">GetAuthor<\/span>(<span class=\"hljs-params\">Book book, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">return<\/span> context.Authors.FirstOrDefault(a =&gt; a.Id == book.AuthorId);\n        }\n\n        <span class=\"hljs-comment\">\/\/ Custom resolver for fetching a list of books.<\/span>\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IQueryable&lt;Book&gt; <span class=\"hljs-title\">GetBooks<\/span>(<span class=\"hljs-params\">&#91;ScopedService] AppDbContext context<\/span>)<\/span>\n        {\n            <span class=\"hljs-keyword\">return<\/span> context.Books;\n        }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Note the use of <code>[ScopedService]<\/code> attribute on the <code>context<\/code> parameter. This ensures that we have a scoped database context available in our resolver, which is essential for database operations. The <code>UseDbContext&lt;AppDbContext&gt;()<\/code> directive is also important as it provides the scoped database context to our resolver.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We&#8217;ve added the <code>GetBooks<\/code> resolver that fetches all the books from the database.<\/li>\n\n\n\n<li>The <code>GetAuthor<\/code> resolver fetches the author for a particular book, demonstrating how we can fetch related data.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">When a client queries for a list of books, HotChocolate will automatically use the <code>GetBooks<\/code> resolver to fetch the required data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Creating Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Resolvers also play a crucial role when it comes to mutations, i.e., changing the data. When a client sends a mutation request, it&#8217;s the resolver that handles the operation and determines the data that&#8217;s returned.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Resolver for adding a new book:<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">To allow clients to add a new book, we&#8217;ll define a mutation resolver. Mutations are typically separate from our type classes, and we&#8217;ll group them based on the operation&#8217;s entity.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s see how to create a resolver for adding a new book:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\n<span class=\"hljs-keyword\">using<\/span> HotChocolate.Types;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Data;\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Models;\n<span class=\"hljs-keyword\">using<\/span> System.Linq;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookMutations<\/span>\n{\n    &#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Mutation\"<\/span>)<\/span>]\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookMutationType<\/span>\n    {\n        <span class=\"hljs-comment\">\/\/ Resolver for adding a new book<\/span>\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Book <span class=\"hljs-title\">AddBook<\/span>(<span class=\"hljs-params\">\n            BookInput input, \/\/ Define an input type <span class=\"hljs-keyword\">for<\/span> our mutation\n            &#91;ScopedService] AppDbContext context<\/span>) <span class=\"hljs-comment\">\/\/ Scoped EF Core DbContext<\/span><\/span>\n        {\n            <span class=\"hljs-keyword\">var<\/span> book = <span class=\"hljs-keyword\">new<\/span> Book\n            {\n                Title = input.Title,\n                ISBN = input.ISBN,\n                PublicationDate = input.PublicationDate,\n                AuthorId = input.AuthorId,\n                PublisherId = input.PublisherId\n            };\n\n            context.Books.Add(book);\n            context.SaveChanges();\n\n            <span class=\"hljs-keyword\">return<\/span> book;\n        }\n    }\n\n    <span class=\"hljs-comment\">\/\/ Define the input type for the 'AddBook' mutation<\/span>\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookInput<\/span>\n    {\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> Title { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span> ISBN { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n        <span class=\"hljs-keyword\">public<\/span> DateTime PublicationDate { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> AuthorId { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> PublisherId { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the breakdown of the code:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We have a <code>BookMutationType<\/code> class that contains our mutation resolvers related to books.<\/li>\n\n\n\n<li>The <code>AddBook<\/code> method is our resolver for adding a new book. This method:\n<ul class=\"wp-block-list\">\n<li>Takes in a <code>BookInput<\/code> object which is a representation of our input data for the mutation.<\/li>\n\n\n\n<li>Uses the provided <code>AppDbContext<\/code> to add the new book to the database and save the changes.<\/li>\n\n\n\n<li>Returns the newly added book.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>The <code>BookInput<\/code> class is an input type that represents the shape of the data we expect from clients when they want to add a new book.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">With this setup, a client can now send a mutation request to add a new book. For instance, the client-side GraphQL mutation might look like:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"SQL (Structured Query Language)\" data-shcb-language-slug=\"sql\"><span><code class=\"hljs language-sql\">mutation {\n  addBook(input: {\n    title: \"New GraphQL Book\",\n    ISBN: \"123456789\",\n    publicationDate: \"2023-10-05\",\n    authorId: 1,\n    publisherId: 1\n  }) {\n    id\n    title\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">SQL (Structured Query Language)<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">sql<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This mutation will use the <code>AddBook<\/code> resolver to add a new book to the database and return the <code>id<\/code> and <code>title<\/code> of the newly added book.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Updating Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When it comes to updating data in our system through GraphQL, we&#8217;ll use mutation resolvers similar to creating data. The difference typically lies in how the resolver handles the provided input\u2014finding the existing data and updating its attributes.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Resolver for updating an existing book&#8217;s details:<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s see how to create a resolver to update an existing book:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\r\n<span class=\"hljs-keyword\">using<\/span> HotChocolate.Types;\r\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Data;\r\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Models;\r\n<span class=\"hljs-keyword\">using<\/span> System.Linq;\r\n\r\n&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Mutation\"<\/span>)<\/span>]\r\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookUpdateMutations<\/span>\r\n{\r\n    <span class=\"hljs-comment\">\/\/ Resolver for updating a book's details<\/span>\r\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Book <span class=\"hljs-title\">UpdateBook<\/span>(<span class=\"hljs-params\">\r\n        UpdateBookInput input, \/\/ Define an input type <span class=\"hljs-keyword\">for<\/span> our mutation\r\n        &#91;ScopedService] AppDbContext context<\/span>) <span class=\"hljs-comment\">\/\/ Scoped EF Core DbContext<\/span><\/span>\r\n    {\r\n        <span class=\"hljs-keyword\">var<\/span> existingBook = context.Books.Find(input.Id);\r\n        \r\n        <span class=\"hljs-keyword\">if<\/span> (existingBook == <span class=\"hljs-literal\">null<\/span>)\r\n            <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> GraphQLException(<span class=\"hljs-string\">$\"Book with ID <span class=\"hljs-subst\">{input.Id}<\/span> not found.\"<\/span>);\r\n\r\n        <span class=\"hljs-keyword\">if<\/span> (!<span class=\"hljs-keyword\">string<\/span>.IsNullOrEmpty(input.Title))\r\n            existingBook.Title = input.Title;\r\n\r\n        <span class=\"hljs-keyword\">if<\/span> (!<span class=\"hljs-keyword\">string<\/span>.IsNullOrEmpty(input.ISBN))\r\n            existingBook.ISBN = input.ISBN;\r\n\r\n        <span class=\"hljs-keyword\">if<\/span> (input.PublicationDate.HasValue)\r\n            existingBook.PublicationDate = input.PublicationDate.Value;\r\n\r\n        <span class=\"hljs-keyword\">if<\/span> (input.AuthorId.HasValue)\r\n            existingBook.AuthorId = input.AuthorId.Value;\r\n\r\n        <span class=\"hljs-keyword\">if<\/span> (input.PublisherId.HasValue)\r\n            existingBook.PublisherId = input.PublisherId.Value;\r\n\r\n        context.SaveChanges();\r\n\r\n        <span class=\"hljs-keyword\">return<\/span> existingBook;\r\n    }\r\n\r\n    <span class=\"hljs-comment\">\/\/ Define the input type for the 'UpdateBook' mutation<\/span>\r\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">UpdateBookInput<\/span>\r\n    {\r\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> Id { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\r\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span>? Title { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\r\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">string<\/span>? ISBN { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\r\n        <span class=\"hljs-keyword\">public<\/span> DateTime? PublicationDate { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\r\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span>? AuthorId { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\r\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span>? PublisherId { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\r\n    }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s what&#8217;s happening in the code:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <code>UpdateBook<\/code> method is our resolver for updating an existing book&#8217;s details. This method:\n<ul class=\"wp-block-list\">\n<li>Fetches the existing book from the database using the provided <code>Id<\/code> from the input.<\/li>\n\n\n\n<li>Checks if the book exists; if not, it throws an exception.<\/li>\n\n\n\n<li>Updates the book&#8217;s attributes based on the provided input.<\/li>\n\n\n\n<li>Saves the changes to the database.<\/li>\n\n\n\n<li>Returns the updated book.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>The <code>UpdateBookInput<\/code> class represents the shape of the data we expect from clients when they want to update a book. The use of nullable fields allows clients to provide only the fields they wish to update.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A client-side GraphQL mutation for updating a book might look like:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">mutation {\r\n  updateBook(input: {\r\n    <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">1<\/span>,\r\n    <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">\"Updated GraphQL Book\"<\/span>,\r\n    <span class=\"hljs-attr\">ISBN<\/span>: <span class=\"hljs-string\">\"987654321\"<\/span>\r\n  }) {\r\n    id\r\n    title\r\n    ISBN\r\n  }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This mutation will use the <code>UpdateBook<\/code> resolver to update the title and ISBN of the book with ID <code>1<\/code> and return the updated <code>id<\/code>, <code>title<\/code>, and <code>ISBN<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Deleting Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Deleting data through a GraphQL API involves creating a mutation resolver that interacts with the database to remove the specified entity based on the provided criteria.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Resolver for deleting a book:<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s create a resolver to delete a book based on its ID:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\r\n<span class=\"hljs-keyword\">using<\/span> HotChocolate.Types;\r\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Data;\r\n<span class=\"hljs-keyword\">using<\/span> YourNamespace.Models;\r\n<span class=\"hljs-keyword\">using<\/span> System.Linq;\r\n\r\n&#91;<span class=\"hljs-meta\">ExtendObjectType(name: <span class=\"hljs-meta-string\">\"Mutation\"<\/span>)<\/span>]\r\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookDeleteMutations<\/span>\r\n{\r\n    <span class=\"hljs-comment\">\/\/ Resolver for deleting a book<\/span>\r\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">bool<\/span> <span class=\"hljs-title\">DeleteBook<\/span>(<span class=\"hljs-params\">\r\n        <span class=\"hljs-keyword\">int<\/span> id, \/\/ We need only the ID to delete the book\r\n        &#91;ScopedService] AppDbContext context<\/span>) <span class=\"hljs-comment\">\/\/ Scoped EF Core DbContext<\/span><\/span>\r\n    {\r\n        <span class=\"hljs-keyword\">var<\/span> existingBook = context.Books.Find(id);\r\n        \r\n        <span class=\"hljs-keyword\">if<\/span> (existingBook == <span class=\"hljs-literal\">null<\/span>)\r\n            <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> GraphQLException(<span class=\"hljs-string\">$\"Book with ID <span class=\"hljs-subst\">{id}<\/span> not found.\"<\/span>);\r\n\r\n        context.Books.Remove(existingBook);\r\n        context.SaveChanges();\r\n\r\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">true<\/span>; <span class=\"hljs-comment\">\/\/ Return true to indicate the operation was successful<\/span>\r\n    }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the breakdown:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <code>DeleteBook<\/code> method is our resolver for deleting a book. This method:\n<ul class=\"wp-block-list\">\n<li>Fetches the book to be deleted from the database using the provided <code>id<\/code>.<\/li>\n\n\n\n<li>Checks if the book exists; if not, it throws an exception.<\/li>\n\n\n\n<li>Removes the book from the database.<\/li>\n\n\n\n<li>Saves the changes to the database.<\/li>\n\n\n\n<li>Returns <code>true<\/code> to indicate the operation was successful.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For the client side, a GraphQL mutation to delete a book might look something like:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\"><span><code class=\"hljs\">mutation {\r\n  deleteBook(id: 1)\r\n}<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This mutation will use the <code>DeleteBook<\/code> resolver to delete the book with ID <code>1<\/code> and return <code>true<\/code> if the operation was successful.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Deletion is a sensitive operation and should be approached with caution. Always ensure:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Proper error handling.<\/li>\n\n\n\n<li>Adequate permissions and validations (you don&#8217;t want just anyone to delete data).<\/li>\n\n\n\n<li>Consider using soft deletes (marking data as deleted without actually removing it) if data retention is important for your use case.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Error Handling in GraphQL<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Effective error handling is essential in any API, and GraphQL is no exception. GraphQL APIs can emit a variety of errors, ranging from validation to server issues. These errors are conveyed to the client in the <code>errors<\/code> field of the response.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Common GraphQL errors and their solutions:<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Field Validation Errors<\/strong>:\n<ul class=\"wp-block-list\">\n<li><strong>Cause<\/strong>: A request asks for a field that doesn&#8217;t exist.<\/li>\n\n\n\n<li><strong>Solution<\/strong>: Check for typos or out-of-date schema on the client side.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Argument Validation Errors<\/strong>:\n<ul class=\"wp-block-list\">\n<li><strong>Cause<\/strong>: The client might provide an argument that isn&#8217;t expected.<\/li>\n\n\n\n<li><strong>Solution<\/strong>: Verify the arguments in the request and ensure they align with the schema.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Authentication and Authorization Errors<\/strong>:\n<ul class=\"wp-block-list\">\n<li><strong>Cause<\/strong>: A client might try to access data they aren&#8217;t authorized to see, or they might not be authenticated.<\/li>\n\n\n\n<li><strong>Solution<\/strong>: Ensure proper authentication and authorization mechanisms. Provide clear error messages so clients can act accordingly (e.g., re-authenticate or request access).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Query Depth Exceeding Limit<\/strong>:\n<ul class=\"wp-block-list\">\n<li><strong>Cause<\/strong>: To prevent overly complex queries that could lead to performance issues, GraphQL servers might limit query depth.<\/li>\n\n\n\n<li><strong>Solution<\/strong>: Restructure the query to reduce its depth or increase the server&#8217;s depth limit (with caution).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Database Errors<\/strong>:\n<ul class=\"wp-block-list\">\n<li><strong>Cause<\/strong>: Issues related to fetching or writing data to the database.<\/li>\n\n\n\n<li><strong>Solution<\/strong>: These errors are usually handled server-side. Ensure the database connection is stable and that queries are structured correctly.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Implementing custom error handling:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">With HotChocolate, you can add custom error handling to provide more context or to log errors for debugging.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Custom Error Filter<\/strong>:Create a class that implements <code>IErrorFilter<\/code> to customize error handling:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">using<\/span> HotChocolate;\r\n\r\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">CustomErrorFilter<\/span> : <span class=\"hljs-title\">IErrorFilter<\/span>\r\n{\r\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IError <span class=\"hljs-title\">OnError<\/span>(<span class=\"hljs-params\">IError error<\/span>)<\/span>\r\n    {\r\n        <span class=\"hljs-comment\">\/\/ You can inspect the error and decide what to do:<\/span>\r\n        <span class=\"hljs-comment\">\/\/ Log the error, modify the error message, etc.<\/span>\r\n        <span class=\"hljs-keyword\">return<\/span> error.WithMessage(<span class=\"hljs-string\">$\"Custom Error: <span class=\"hljs-subst\">{error.Message}<\/span>\"<\/span>);\r\n    }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Register the Error Filter<\/strong>:In <code>Startup.cs<\/code>, register the custom error filter:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddGraphQL(...)\r\n        .AddErrorFilter&lt;CustomErrorFilter&gt;();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Handle Errors in Resolvers<\/strong>:If you encounter an error in your resolver, you can throw a specific exception. This exception can then be handled by your error filter:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&#91;<span class=\"hljs-meta\">UseExceptionHandler<\/span>]\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Book <span class=\"hljs-title\">AddBook<\/span>(<span class=\"hljs-params\">BookInput input, &#91;ScopedService] AppDbContext context<\/span>)<\/span>\r\n{\r\n    <span class=\"hljs-comment\">\/\/ ... Logic ...<\/span>\r\n\r\n    <span class=\"hljs-keyword\">if<\/span> (someErrorCondition)\r\n    {\r\n        <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> GraphQLException(<span class=\"hljs-string\">\"A custom error occurred while adding the book.\"<\/span>);\r\n    }\r\n\r\n    <span class=\"hljs-comment\">\/\/ ... More Logic ...<\/span>\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In the example above, if <code>someErrorCondition<\/code> is true, a custom error is thrown. This error will be captured by our <code>CustomErrorFilter<\/code>, and the message will be modified before being sent to the client.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Implementing Authorization and Authentication<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Implementing authentication and authorization is essential to secure your GraphQL API. Authentication verifies the identity of a user, while authorization determines what an authenticated user can access.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Integrating JWT with GraphQL:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Setting up JWT Middleware<\/strong>:First, ensure your application is set up to issue and validate JWT tokens, often done with ASP.NET Core&#8217;s built-in JWT bearer authentication middleware.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ In Startup.cs - ConfigureServices method<\/span>\r\n\r\nservices.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\r\n        .AddJwtBearer(options =&gt;\r\n        {\r\n            options.TokenValidationParameters = <span class=\"hljs-keyword\">new<\/span> TokenValidationParameters\r\n            {\r\n                ValidateIssuer = <span class=\"hljs-literal\">true<\/span>,\r\n                ValidateAudience = <span class=\"hljs-literal\">true<\/span>,\r\n                ValidateLifetime = <span class=\"hljs-literal\">true<\/span>,\r\n                ValidateIssuerSigningKey = <span class=\"hljs-literal\">true<\/span>,\r\n                ValidIssuer = Configuration&#91;<span class=\"hljs-string\">\"Jwt:Issuer\"<\/span>],\r\n                ValidAudience = Configuration&#91;<span class=\"hljs-string\">\"Jwt:Audience\"<\/span>],\r\n                IssuerSigningKey = <span class=\"hljs-keyword\">new<\/span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration&#91;<span class=\"hljs-string\">\"Jwt:Key\"<\/span>]))\r\n            };\r\n        });<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Applying Authentication to GraphQL<\/strong>:Ensure authentication middleware is applied before GraphQL in the request pipeline.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ In Startup.cs - Configure method<\/span>\r\n\r\napp.UseAuthentication();\r\napp.UseAuthorization();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Protecting specific fields or types with authorization:<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">With HotChocolate, you can use the <code>[Authorize]<\/code> attribute to protect specific fields or types.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Protecting a Type<\/strong>:You can protect an entire type by applying the <code>[Authorize]<\/code> attribute. This ensures that only authenticated users can access this type.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">&#91;<span class=\"hljs-meta\">Authorize<\/span>]\r\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookType<\/span> : <span class=\"hljs-title\">ObjectType<\/span>&lt;<span class=\"hljs-title\">Book<\/span>&gt;\r\n{\r\n    <span class=\"hljs-comment\">\/\/ ... Type configuration ...<\/span>\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Protecting a Field<\/strong>:If you want to protect just a specific field, you can apply the <code>[Authorize]<\/code> attribute to that field.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookType<\/span> : <span class=\"hljs-title\">ObjectType<\/span>&lt;<span class=\"hljs-title\">Book<\/span>&gt;\r\n{\r\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IObjectTypeDescriptor&lt;Book&gt; descriptor<\/span>)<\/span>\r\n    {\r\n        descriptor.Field(b =&gt; b.Title).Authorize();\r\n        <span class=\"hljs-comment\">\/\/ ... other configurations ...<\/span>\r\n    }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Role-Based Authorization<\/strong>:You can also implement role-based authorization using the <code>[Authorize]<\/code> attribute.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/ Only users with the \"Admin\" role can access this field<\/span>\r\ndescriptor.Field(b =&gt; b.ISBN).Authorize(<span class=\"hljs-string\">\"Admin\"<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Custom Authorization<\/strong>:If you need more fine-grained control, you can implement custom authorization policies in ASP.NET Core and then reference them in your GraphQL types or fields.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddAuthorization(options =&gt;\r\n{\r\n    options.AddPolicy(<span class=\"hljs-string\">\"CustomPolicy\"<\/span>, policy =&gt; \r\n        policy.RequireClaim(<span class=\"hljs-string\">\"CustomClaim\"<\/span>, <span class=\"hljs-string\">\"ClaimValue\"<\/span>));\r\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Then, in your GraphQL type:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">services.AddAuthorization(options =&gt;\r\n{\r\n    options.AddPolicy(<span class=\"hljs-string\">\"CustomPolicy\"<\/span>, policy =&gt; \r\n        policy.RequireClaim(<span class=\"hljs-string\">\"CustomClaim\"<\/span>, <span class=\"hljs-string\">\"ClaimValue\"<\/span>));\r\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-35\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">When implementing authentication and authorization, always test thoroughly to ensure security requirements are met. Consider edge cases and ensure that unauthorized access is effectively prevented. Make sure that error messages from authentication or authorization failures don&#8217;t reveal too much information about your system&#8217;s internal workings or configurations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Optimizing Your GraphQL API<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As with any API, performance and scalability concerns are vital in GraphQL. One of the common pitfalls in GraphQL is the <strong>N+1 problem<\/strong>, where, for example, retrieving an author for each book in a list of books results in one request for the list and then an additional request for the author of each book.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Luckily, a solution exists in the form of <strong>DataLoader<\/strong>. DataLoader is a generic utility that batches and caches requests, vastly improving the performance of our GraphQL API.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Benefits of using DataLoader:<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Batching<\/strong>: Multiple requests to retrieve a type are batched into a single request, reducing the total number of database hits.<\/li>\n\n\n\n<li><strong>Caching<\/strong>: Results from the database are cached in memory to prevent redundant requests during the lifecycle of a single GraphQL request.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Batch and cache requests to reduce database hits:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Without DataLoader, if we had a query fetching multiple books and their authors, the execution might result in separate database requests for each author. With DataLoader, all these requests can be batched, and the authors fetched in a single query.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implementing DataLoader in C#:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s see how we can implement DataLoader in a C# GraphQL setup:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Install Required Packages<\/strong>:If you&#8217;re using HotChocolate, you can use its built-in DataLoader support. First, install the required package:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">Install-Package HotChocolate.DataLoader<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Create a DataLoader<\/strong>:For our example, let&#8217;s create an <code>AuthorDataLoader<\/code> that fetches authors by their IDs.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AuthorDataLoader<\/span> : <span class=\"hljs-title\">BatchDataLoader<\/span>&lt;<span class=\"hljs-title\">int<\/span>, <span class=\"hljs-title\">Author<\/span>&gt;\r\n{\r\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> AppDbContext _dbContext;\r\n\r\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">AuthorDataLoader<\/span>(<span class=\"hljs-params\">AppDbContext dbContext<\/span>)<\/span>\r\n    {\r\n        _dbContext = dbContext;\r\n    }\r\n\r\n    <span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;IReadOnlyDictionary&lt;<span class=\"hljs-keyword\">int<\/span>, Author&gt;&gt; LoadBatchAsync(\r\n        IReadOnlyList&lt;<span class=\"hljs-keyword\">int<\/span>&gt; keys, \r\n        CancellationToken cancellationToken)\r\n    {\r\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">await<\/span> _dbContext.Authors\r\n            .Where(a =&gt; keys.Contains(a.Id))\r\n            .ToDictionaryAsync(t =&gt; t.Id, cancellationToken);\r\n    }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Use DataLoader in Resolvers<\/strong>:Now, when resolving fields, use the DataLoader to fetch data:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BookType<\/span> : <span class=\"hljs-title\">ObjectType<\/span>&lt;<span class=\"hljs-title\">Book<\/span>&gt;\r\n{\r\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">protected<\/span> <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Configure<\/span>(<span class=\"hljs-params\">IObjectTypeDescriptor&lt;Book&gt; descriptor<\/span>)<\/span>\r\n    {\r\n        descriptor.Field(b =&gt; b.Author)\r\n            .ResolveWith&lt;Resolvers&gt;(r =&gt; r.GetAuthor(<span class=\"hljs-keyword\">default<\/span>!, <span class=\"hljs-keyword\">default<\/span>!));\r\n    }\r\n\r\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Resolvers<\/span>\r\n    {\r\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;Author&gt; <span class=\"hljs-title\">GetAuthor<\/span>(<span class=\"hljs-params\">Book book, AuthorDataLoader authorLoader<\/span>)<\/span>\r\n        {\r\n            <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">await<\/span> authorLoader.LoadAsync(book.AuthorId);\r\n        }\r\n    }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In the example above, when multiple books are fetched, and the author for each book needs to be retrieved, DataLoader will ensure that authors are fetched in a single batch, dramatically reducing the number of database hits.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using DataLoader can greatly enhance the efficiency and performance of your GraphQL API, especially when dealing with complex queries that fetch related data. By batching and caching requests, DataLoader ensures that your API remains scalable and responsive even under heavy loads.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Testing the CRUD Operations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Once you&#8217;ve set up your GraphQL API, it&#8217;s essential to test the CRUD operations to ensure everything works as expected. Tools like GraphQL Playground and Postman make this process straightforward and intuitive.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Using GraphQL Playground or Postman:<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>GraphQL Playground<\/strong>: This is an interactive, in-browser GraphQL IDE. If you&#8217;re using HotChocolate, GraphQL Playground comes integrated, and you can access it by navigating to <code>\/graphql<\/code> in your browser after starting your server.<\/li>\n\n\n\n<li><strong>Postman<\/strong>: Postman introduced support for GraphQL, allowing you to test GraphQL APIs just like any other API. To use Postman, set the HTTP verb to POST and set the body type to GraphQL. Provide the GraphQL endpoint URL, and you&#8217;re set to test your queries and mutations.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Sample queries and mutations for testing:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fetch all books<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\"><span><code class=\"hljs\">query {\r\n  getBooks {\r\n    id\r\n    title\r\n    author {\r\n      name\r\n    }\r\n  }\r\n}<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Fetch a single book<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\"><span><code class=\"hljs\">query {\r\n  getBook(id: 1) {\r\n    title\r\n    ISBN\r\n    author {\r\n      name\r\n    }\r\n  }\r\n}<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Add a new book<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\" aria-describedby=\"shcb-language-39\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">mutation {\r\n  addBook(input: {\r\n    <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">\"New Book\"<\/span>,\r\n    <span class=\"hljs-attr\">ISBN<\/span>: <span class=\"hljs-string\">\"123-456\"<\/span>,\r\n    <span class=\"hljs-attr\">publicationDate<\/span>: <span class=\"hljs-string\">\"2023-10-05\"<\/span>,\r\n    <span class=\"hljs-attr\">authorId<\/span>: <span class=\"hljs-number\">1<\/span>,\r\n    <span class=\"hljs-attr\">publisherId<\/span>: <span class=\"hljs-number\">2<\/span>\r\n  }) {\r\n    id\r\n    title\r\n  }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Update a book<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">mutation {\r\n  updateBook(input: {\r\n    <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">1<\/span>,\r\n    <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">\"Updated Book Title\"<\/span>\r\n  }) {\r\n    id\r\n    title\r\n  }\r\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-40\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Delete a book<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code lang-graphql\"><span><code class=\"hljs\">mutation {\r\n  deleteBook(id: 1)\r\n}<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">You can run these queries and mutations in either GraphQL Playground or Postman to test the operations of your GraphQL API. Ensure to check the responses for correctness and inspect any errors returned. It&#8217;s also wise to look into your database directly to verify that the expected changes (especially for mutations) took place.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Best Practices<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ensuring best practices in your GraphQL API can lead to better performance, maintainability, and extensibility. Let&#8217;s delve into some important best practices to consider.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Schema Design Recommendations:<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Descriptive Naming<\/strong>: Name your types and fields descriptively. Avoid jargon that clients of the API might not understand.<\/li>\n\n\n\n<li><strong>Use Enums and Scalars<\/strong>: For fields that have a specific set of possible values, consider using Enums. Similarly, use custom scalars for specific data types not covered by GraphQL&#8217;s default scalars (like Date or DateTime).<\/li>\n\n\n\n<li><strong>Avoid Null Where Possible<\/strong>: While GraphQL supports nullable types, it&#8217;s often better to avoid them unless there&#8217;s a compelling reason. This ensures clients always receive meaningful data.<\/li>\n\n\n\n<li><strong>Limit Deep Nesting<\/strong>: While GraphQL allows clients to request deeply nested data, consider limiting the depth to prevent overly complex queries.<\/li>\n\n\n\n<li><strong>Use Input Types for Mutations<\/strong>: Instead of having many arguments for mutations, group them into an input type for clarity.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Versioning in GraphQL:<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Avoid Versioning if Possible<\/strong>: One of GraphQL&#8217;s strengths is its ability to evolve without versioning. Adding fields is non-breaking. Removing or changing fields can be managed by marking them as deprecated.<\/li>\n\n\n\n<li><strong>Schema Extensions<\/strong>: If you must introduce breaking changes, consider extending the schema. For example, introduce new types or fields and deprecate old ones.<\/li>\n\n\n\n<li><strong>Clear Deprecation Messages<\/strong>: When deprecating fields or types, provide clear and meaningful deprecation messages.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Handling N+1 Problem:<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Use DataLoader<\/strong>: As covered earlier, DataLoader is an invaluable tool in resolving the N+1 problem by batching and caching requests.<\/li>\n\n\n\n<li><strong>Opt for Batched Endpoints<\/strong>: If integrating with other services, consider batched endpoints that retrieve multiple items in one go.<\/li>\n\n\n\n<li><strong>Limit Field Complexity<\/strong>: It&#8217;s good to allow clients the flexibility to request the data they need. However, it might be wise to implement query complexity analysis to prevent overly complicated queries.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">GraphQL&#8217;s flexibility can be a double-edged sword, leading to potential pitfalls like performance bottlenecks if not managed correctly. Leveraging best practices, utilizing tools like DataLoader, and regularly testing your API are all vital steps in ensuring your GraphQL API remains performant, secure, and scalable.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction What is GraphQL? GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data. Unlike other API standards that focus on defining fixed endpoints, GraphQL enables clients to request exactly the data they need, and no more. Developed by [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[8,4],"tags":[],"class_list":["post-1569","post","type-post","status-publish","format-standard","category-csharp","category-programming-languages","entry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building a CRUD API with C# and GraphQL<\/title>\n<meta name=\"description\" content=\"GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a CRUD API with C# and GraphQL\" \/>\n<meta property=\"og:description\" content=\"GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-10-07T02:44:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-10-07T02:44:13+00:00\" \/>\n<meta name=\"author\" content=\"w3compadmin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"w3compadmin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/\"},\"author\":{\"name\":\"w3compadmin\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"headline\":\"Building a CRUD API with C# and GraphQL\",\"datePublished\":\"2023-10-07T02:44:11+00:00\",\"dateModified\":\"2023-10-07T02:44:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/\"},\"wordCount\":4068,\"commentCount\":0,\"articleSection\":[\"C#\",\"Programming Languages\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/\",\"name\":\"Building a CRUD API with C# and GraphQL\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\"},\"datePublished\":\"2023-10-07T02:44:11+00:00\",\"dateModified\":\"2023-10-07T02:44:13+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"description\":\"GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-crud-api-with-csharp-graphql\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Articles Home\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Programming Languages\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/programming-languages\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Building a CRUD API with C# and GraphQL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\",\"name\":\"Developer Articles Hub\",\"description\":\"\",\"alternateName\":\"Developer Articles\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\",\"name\":\"w3compadmin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"contentUrl\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"caption\":\"w3compadmin\"},\"sameAs\":[\"http:\\\/\\\/w3computing.com\\\/articles\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building a CRUD API with C# and GraphQL","description":"GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/","og_locale":"en_US","og_type":"article","og_title":"Building a CRUD API with C# and GraphQL","og_description":"GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data.","og_url":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/","article_published_time":"2023-10-07T02:44:11+00:00","article_modified_time":"2023-10-07T02:44:13+00:00","author":"w3compadmin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"w3compadmin","Est. reading time":"18 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/#article","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/"},"author":{"name":"w3compadmin","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"headline":"Building a CRUD API with C# and GraphQL","datePublished":"2023-10-07T02:44:11+00:00","dateModified":"2023-10-07T02:44:13+00:00","mainEntityOfPage":{"@id":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/"},"wordCount":4068,"commentCount":0,"articleSection":["C#","Programming Languages"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/","url":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/","name":"Building a CRUD API with C# and GraphQL","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/#website"},"datePublished":"2023-10-07T02:44:11+00:00","dateModified":"2023-10-07T02:44:13+00:00","author":{"@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"description":"GraphQL is a query language for APIs, as well as a runtime for executing those queries using a type system that you define for your data.","breadcrumb":{"@id":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.w3computing.com\/articles\/building-crud-api-with-csharp-graphql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Articles Home","item":"https:\/\/www.w3computing.com\/articles\/"},{"@type":"ListItem","position":2,"name":"Programming Languages","item":"https:\/\/www.w3computing.com\/articles\/programming-languages\/"},{"@type":"ListItem","position":3,"name":"Building a CRUD API with C# and GraphQL"}]},{"@type":"WebSite","@id":"https:\/\/www.w3computing.com\/articles\/#website","url":"https:\/\/www.w3computing.com\/articles\/","name":"Developer Articles Hub","description":"","alternateName":"Developer Articles","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.w3computing.com\/articles\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561","name":"w3compadmin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","url":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","contentUrl":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","caption":"w3compadmin"},"sameAs":["http:\/\/w3computing.com\/articles"]}]}},"featured_image_src":null,"featured_image_src_square":null,"author_info":{"display_name":"w3compadmin","author_link":"https:\/\/www.w3computing.com\/articles\/author\/w3compadmin\/"},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/1569","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/comments?post=1569"}],"version-history":[{"count":13,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/1569\/revisions"}],"predecessor-version":[{"id":1582,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/1569\/revisions\/1582"}],"wp:attachment":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/media?parent=1569"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/categories?post=1569"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/tags?post=1569"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}