{"id":82844,"date":"2019-01-07T22:46:58","date_gmt":"2019-01-07T22:46:58","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=82844"},"modified":"2026-03-06T11:19:13","modified_gmt":"2026-03-06T11:19:13","slug":"getting-started-with-graphql-in-asp-net","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/getting-started-with-graphql-in-asp-net\/","title":{"rendered":"GraphQL in ASP.NET: REST Comparison &#038; C# Tutorial"},"content":{"rendered":"\n<p>GraphQL is a query language for APIs that lets clients request exactly the data they need in a single HTTP request, eliminating the over-fetching and under-fetching problems common with REST endpoints. In ASP.NET, you implement GraphQL by defining a schema with types and resolvers, then exposing a single endpoint that handles queries and mutations. This tutorial builds a working GraphQL API in ASP.NET Core with C#, walking through the architecture differences between REST and GraphQL, setting up schema types, writing resolvers, and testing with GraphQL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-the-basics-of-graphql\">The basics of GraphQL<\/h2>\n\n\n\n<p><a href=\"https:\/\/graphql.org\/\">GraphQL<\/a> has been around for a while and is proving its value. It is not, unlike what\u2019s been spread about, a framework or just a ready-tool for dealing with HTTP-based searches. Just like REST is a specification to access resources that partially expose the business models in client-server applications, GraphQL is a cleaner, more flexible way to execute and fetch specific data from the server.<\/p>\n\n\n\n<p>In other words: <em>ask for hat you need, get exactly that<\/em>. That\u2019s the anthem of GraphQL. Instead of having tons of different REST endpoints to provide access to every resource via a different HTTP request, you can do the same thing with only a single request, along with a smarter (smaller \u2013 just what you need) response body, getting summarized data from different resources.<\/p>\n\n\n\n<p>It also comes with a strong type system, encapsulated in a syntax that resembles JSON. Also, you don\u2019t need to worry about versioning the endpoints since you can deprecate your fields once they become old. And it is available for all the major languages for both client and server sides. Because of its committed community, you can find many different open source clients and projects being broadly supported around the world.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-general-architecture\">General Architecture<\/h2>\n\n\n\n<p>Think about graphs. In theory, they are used to mathematically model the relations two objects have in common. In GraphQL, you start to join this concept with a query language in order to fetch\/send all the data you need with no more endpoints.<\/p>\n\n\n\n<p>In a common REST API, developers grab information from endpoints that represent a single and understandable source of information, a resource. Usually, they return a lot of data, most of this not necessary for the current operation, making the whole conversation too verbose. Plus, since each resource hosts different data, you\u2019d need to go through many of them to catch everything turning the calling to the server too chatty:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1300\" height=\"734\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-63.png\" alt=\"\" class=\"wp-image-82845\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>GraphQL, on the other hand, summarizes everything the client needs at once, by allowing you to specify all the data in a query fully supported by the back-end. One single HTTP request, all the data you need in hands:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1477\" height=\"1065\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-64.png\" alt=\"\" class=\"wp-image-82846\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>This way, GraphQL minimizes a lot of the over and under fetching issues that most modern applications deal with in addition to letting the front-end be freer to mount the request chaining the way they see it\u2019s best.<\/p>\n\n\n\n<p>Because of its HTTP-based nature, GraphQL also benefits from all the out-of-the-box features that REST did, including the stateless state, patterns, free from tech stack and heavily embraced by the community. Also, you can create your APIs within any supported language, just the same way you would with the clients. <a href=\"https:\/\/graphql.org\/code\/\">Most of the big platforms<\/a> already support it.<\/p>\n\n\n\n<p><strong>Read also:<\/strong> <a href=\"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/jwt-authentication-microservices-net\/\" target=\"_blank\" rel=\"noreferrer noopener\">JWT authentication for securing APIs<\/a><\/p>\n\n\n\n<p>Another important feature that comes with GraphQL are the <strong>resolvers<\/strong>. They basically allow the extraction of data from different sources and integrate the data into the same response. It is useful when you want to connect data that relates to the query objects are being fetched now, while accessing resources sometimes even via remote calls to other services. This architectural design, of course, can lead to slowness depending on the way you make each call. Remember, even though it\u2019s a great feature to use, each integration you have in a single query can lead to more and more delay to the user\u2019s response, so be careful just the same way you should be when designing REST web services. Finally, you also have to remember that a query still has to fetch relatable data, which means that a query that searches for a user data has nothing to do with your stockroom\u2019s system data. So, keep anchored to your original design and make data design meaningful.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-demo-project\">Demo Project<\/h2>\n\n\n\n<p>You have an idea about GraphQL basics, and now it\u2019s time to practice with a relatable example. For this, you will go through an example that explores a comparison between an old fashion approach (REST) vs. the same thing with GraphQL. The Simple Talk author\u2019s page will be the front-end client of a web service that returns the data necessary to build it.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1761\" height=\"981\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-65.png\" alt=\"\" class=\"wp-image-82847\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In a common REST application, you\u2019d have the following endpoints to retrieve the JSON\/XML\/etc. data:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>\/authors\/{id} \u2013 the core information related to user of id referenced at <em>{id} <\/em>path param;<\/li>\n\n\n\n<li>\/authors\/{id}\/posts \u2013 the posts data related to user of id referenced at <em>{id} <\/em>path param;<\/li>\n\n\n\n<li>\/authors\/{id}\/socials \u2013 the social networks related to user of id referenced at <em>{id} <\/em>path param.<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Therefore, REST is so chatty. For every new compositional data, that is related to a specific user, a new endpoint that identifies it is born, meaning that a new request must happen.<\/p>\n\n\n\n<p>Instead, using GraphQL, you\u2019d need a query like this one:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">query GetBlogData($id: Int!) {\n  author(id: $id) {\n    \/\/ author core data\n  }\n  posts(id: $id) {\n    \/\/ posts list\n  }\n  socials(id: $id) {\n    \/\/ social networks list\n  }\n}<\/pre>\n\n\n\n<p>Inside of each query member, you can fetch just the exact information you want. It is contrary to REST, where each endpoint would return all the information related to a post or a social network, making the whole response heavier than what you need.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-environment-and-setup\">Environment and Setup<\/h2>\n\n\n\n<p>To get started, create a new ASP.NET Core Web Application called GraphQL-SimpleTalk using the New Project wizard in VS. You can use the Visual Studio Community Edition. For this, you must have the latest version of .NET Core SDK installed in your environment.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1178\" height=\"816\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-66.png\" alt=\"\" class=\"wp-image-82848\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In the next screen, select the project template <em>API<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"985\" height=\"692\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-67.png\" alt=\"\" class=\"wp-image-82849\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Once with the project created, add the NuGet dependencies for GraphQL. Right-click the solution and go to NuGet manager. There, search for two dependencies:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>GraphQL: the core, parsers, Linq adapters, etc.<\/li>\n\n\n\n<li>GraphiQL: the UI necessary to perform the tests<\/li>\n<\/ul>\n<\/div>\n\n\n<p>That\u2019s all. To simplify this article, you\u2019ll create a service layer and manage objects in lists in memory. This way, you don\u2019t have to worry about further integrations and details that don\u2019t relate to the article purposes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-the-project-implementation\">The Project Implementation<\/h2>\n\n\n\n<p>The first part of the project to create are the models. They\u2019ll drive the rest of the implementation, and they are called entities (supposedly the ones that would attach to a database context). Take a look at the following diagram:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"710\" height=\"490\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-68.png\" alt=\"\" class=\"wp-image-82850\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Idealistically, there would be more fields and relations happening here. However, this model keeps as close as possible to what is the ST\u2019s authors page. Plus, the socials and posts models are separate from the author itself, since you\u2019ll search them through the in-memory lists to return in separate service methods.<\/p>\n\n\n\n<p><strong>Read also:<\/strong><br><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/working-with-json-in-sql-server\/\" target=\"_blank\" rel=\"noreferrer noopener\">JSON handling in SQL Server<\/a><br><a href=\"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/a-practical-guide-to-dapper\/\" target=\"_blank\" rel=\"noreferrer noopener\">Dapper for direct SQL data access<\/a><\/p>\n\n\n\n<p>Continuing, inside the project, create a new folder <em>Entities<\/em> and create several classes.<\/p>\n\n\n\n<p>The <code>Author<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">namespace GraphQL_SimpleTalk.Entities\n{\n    public class Author\n    {\n        public int Id { get; set; }\n        public string Name { get; set; }\n        public string Bio { get; set; }\n        public string ImgUrl { get; set; }\n        public string ProfileUrl { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>The <code>Comment<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">namespace GraphQL_SimpleTalk.Entities\n{\n    public class Comment\n    {\n        public string Url { get; set; }\n        public string Description { get; set; }\n        public int Count { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>The <code>Rating<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">namespace GraphQL_SimpleTalk.Entities\n{\n    public class Rating\n    {\n        public int Percent { get; set; }\n        public int Count { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>The <code>Post<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using System;\nusing System.Collections.Generic;\nnamespace GraphQL_SimpleTalk.Entities\n{\n    public class Post\n    {\n        public int Id { get; set; }\n        public string Title { get; set; }\n        public string Description { get; set; }\n        public DateTime Date { get; set; }\n        public string Url { get; set; }\n        public Author Author { get; set; }\n        public string[] Categories { get; set; }\n        public Rating Rating { get; set; }\n        public List&lt;Comment&gt; Comments { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>The <code>SocialNetwork<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">namespace GraphQL_SimpleTalk.Entities\n{\n    public class SocialNetwork\n    {\n        public SNType Type { get; set; }\n        public string NickName { get; set; }\n        public string Url { get; set; }\n        public Author Author { get; set; }\n    }\n    public enum SNType\n    {\n        INSTAGRAM, TWITTER\n    }\n}<\/pre>\n\n\n\n<p>Make sure to create each one of them in a separate class file. Here, you also had to change the namespace from <code>GraphQL-SimpleTalk<\/code> to <code>GraphQL_SimpleTalk<\/code>, because .NET doesn\u2019t accept hyphens for names.<\/p>\n\n\n\n<p>They\u2019re just simple POJO (plain old Java objects) structural objects to simulate what you\u2019d have in a real database-based API application. You can also turn them into DDD (Domain Driven Design) objects to host business logic or important operations for your API.<\/p>\n\n\n\n<p>The <code>SocialNetwork<\/code> has an enum (<code>SNType<\/code>) to host the types of social media the author could possibly have. It will be interesting to demonstrate how to deal with enums in GraphQL as well.<\/p>\n\n\n\n<p>Now, move to the service layer. You\u2019re going to create a single service class that will provide access to the main data related to the blog. Since it\u2019s not the focus of the project, not much time will be spent on it. Again, create a new folder <em>Services<\/em> and add the following class inside:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL_SimpleTalk.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nnamespace GraphQL_SimpleTalk.Services\n{\n    public class BlogService\n    {\n        private readonly List&lt;Author&gt; authors = new List&lt;Author&gt;();\n        private readonly List&lt;Post&gt; posts = new List&lt;Post&gt;();\n        private readonly List&lt;SocialNetwork&gt; sns = new List&lt;SocialNetwork&gt;();\n        \n        public BlogService()\n        {\n            Author DinoEsposito = new Author\n            {\n                Id = 1,\n                Name = \"Dino Esposito\",\n                Bio = \"Dino Esposito has authored more than 20 books and 1,000 articles in ...\",\n                ImgUrl = \"https:\/\/secure.gravatar.com\/avatar\/ace158af8dfab0e682dcc70d965514e5?s=80&amp;d=mm&amp;r=g\",\n                ProfileUrl = \"https:\/\/www.red-gate.com\/simple-talk\/author\/dino-esposito\/\"\n            };\n            Author LanceTalbert = new Author\n            {\n                Id = 2,\n                Name = \"Lance Talbert\",\n                Bio = \"Lance Talbert is a budding game developer that has been learning to program since ...\",\n                ImgUrl = \"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/01\/red-gate-bio-pic.jpg\",\n                ProfileUrl = \"https:\/\/www.red-gate.com\/simple-talk\/author\/lancetalbert\/\"\n            };\n            authors.Add(DinoEsposito);\n            authors.Add(LanceTalbert);\n            Comment comment1 = new Comment\n            {\n                Url = \"https:\/\/#\",\n                Description = \"Bla bla bla\",\n                Count = 1\n            };\n            Comment comment2 = new Comment\n            {\n                Url = \"https:\/\/#\",\n                Description = \"Bla bla bla\",\n                Count = 4\n            };\n            Rating rating1 = new Rating\n            {\n                Percent = 98,\n                Count = 1\n            };\n            Rating rating2 = new Rating\n            {\n                Percent = 95,\n                Count = 5\n            };\n            Post FormsInVanilla = new Post\n            {\n                Id = 1,\n                Title = \"Building Better HTML Forms in Vanilla-JS\",\n                Description = \"Creating forms is one of the most basic skills for a web developer...\",\n                Date = DateTime.Today,\n                Url = \"https:\/\/www.red-gate.com\/simple-talk\/dotnet\/net-development\/building-better-html-forms-in-vanilla-js\/\",\n                Author = DinoEsposito,\n                Comments = new List&lt;Comment&gt;() { comment1 },\n                Rating = rating1,\n                Categories = new string[] { \".NET Development\" }\n            };\n            Post VoiceCommands = new Post\n            {\n                Id = 2,\n                Title = \"Voice Commands in Unity\",\n                Description = \"Today, we use voice in many ways. We can order groceries...\",\n                Date = DateTime.Today,\n                Url = \"https:\/\/www.red-gate.com\/simple-talk\/dotnet\/c-programming\/voice-commands-in-unity\/\",\n                Author = LanceTalbert,\n                Comments = new List&lt;Comment&gt;() { comment2 },\n                Rating = rating2,\n                Categories = new string[] { \"C# programming\" }\n            };\n            posts.Add(FormsInVanilla);\n            posts.Add(VoiceCommands);\n            SocialNetwork sn1 = new SocialNetwork()\n            {\n                Type = SNType.INSTAGRAM,\n                Author = DinoEsposito,\n                NickName = \"@dino\",\n                Url = \"https:\/\/#\"\n            };\n            SocialNetwork sn2 = new SocialNetwork()\n            {\n                Type = SNType.TWITTER,\n                Author = DinoEsposito,\n                NickName = \"@dino\",\n                Url = \"https:\/\/#\"\n            };\n            sns.Add(sn1);\n            sns.Add(sn2);\n        }\n        public List&lt;Author&gt; GetAllAuthors()\n        {\n            return this.authors;\n        }\n        public Author GetAuthorById(int id)\n        {\n            return authors.Where(author =&gt; author.Id == id).FirstOrDefault&lt;Author&gt;();\n        }\n        public List&lt;Post&gt; GetPostsByAuthor(int id)\n        {\n            return posts.Where(post =&gt; post.Author.Id == id).ToList&lt;Post&gt;();\n        }\n        public List&lt;SocialNetwork&gt; GetSNsByAuthor(int id)\n        {\n            return sns.Where(sn =&gt; sn.Author.Id == id).ToList&lt;SocialNetwork&gt;();\n        }\n    }\n}<\/pre>\n\n\n\n<p>This is mostly boilerplate code. It spends some time to create data and feed the lists necessary to handle the main operations of getting them and sending back to the clients. Feel free to add as much data as you want to make the example even more real, or even connect to a different data source.<\/p>\n\n\n\n<p>The get methods were built in a way to simulate the REST operations of getting each resource through a different endpoint plus the identifier of its parent.<\/p>\n\n\n\n<p>Last, but not least, create the controller class (for the REST example) that will provide each endpoint pointed out before. Inside the <em>Controllers<\/em> folder, add the following controller class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL_SimpleTalk.Services;\nusing Microsoft.AspNetCore.Mvc;\nnamespace GraphQL_SimpleTalk.Controllers\n{\n    [Route(\"api\/[controller]\")]\n    [ApiController]\n    public class AuthorsController : ControllerBase\n    {\n        private readonly BlogService blogService;\n        public AuthorsController(BlogService blogService)\n        {\n            this.blogService = blogService;\n        }\n        [HttpGet]\n        public IActionResult GetAll()\n        {\n            return new ObjectResult(blogService.GetAllAuthors());\n        }\n        [HttpGet(\"{id}\")]\n        public IActionResult GetAuthorById(int id)\n        {\n            return new ObjectResult(blogService.GetAuthorById(id));\n        }\n        [HttpGet(\"{id}\/posts\")]\n        public IActionResult GetPostsByAuthor(int id)\n        {\n            return new ObjectResult(blogService.GetPostsByAuthor(id));\n        }\n        [HttpGet(\"{id}\/socials\")]\n        public IActionResult GetSocialsByAuthor(int id)\n        {\n            return new ObjectResult(blogService.GetSNsByAuthor(id));\n        }\n    }\n}<\/pre>\n\n\n\n<p>Note how simple it is &#8212; if you\u2019re used to dealing with REST APIs in ASP.NET, of course. The code is basically encapsulating the <code>BlogService<\/code> service to access its operations for every endpoint. For now, the code is handling only GET HTTP operations.<\/p>\n\n\n\n<p>That\u2019s pretty much everything we need to run the example. But, before testing, don\u2019t forget to add the scoped declaration of the <code>BlogService<\/code> service to the <code>Startup<\/code> class, inside the <code>ConfigureServices()<\/code> method:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">services.AddScoped&lt;BlogService&gt;();<\/pre>\n\n\n\n<p>And you also need to import the respective class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL_SimpleTalk.Services;<\/pre>\n\n\n\n<p>Now, start the server, go to your web browser and test each of the endpoints. Note that you may have a different port than shown here:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/localhost:44360\/api\/authors\/1\">https:\/\/localhost:44360\/api\/authors\/1<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"959\" height=\"392\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-69.png\" alt=\"\" class=\"wp-image-82851\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/localhost:44360\/api\/authors\/1\/posts\">https:\/\/localhost:44360\/api\/authors\/1\/posts<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1166\" height=\"786\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-70.png\" alt=\"\" class=\"wp-image-82852\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/localhost:44360\/api\/authors\/1\/socials\">https:\/\/localhost:44360\/api\/authors\/1\/socials<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1002\" height=\"706\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-71.png\" alt=\"\" class=\"wp-image-82853\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>It seems simple, doesn\u2019t it? What happens when you scale this conversational design to millions, billions of requests\/responses per day?<\/p>\n\n\n\n<p>Now to see how GraphQL addresses the same scenario.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-the-graphql-approach\">The GraphQL Approach<\/h2>\n\n\n\n<p>Initially, set the GraphiQL up. <a href=\"https:\/\/github.com\/graphql\/graphiql\">GraphiQL<\/a> (a NuGet dependency you\u2019ve already installed) is an in-browser IDE for exploring GraphQL. It saves a lot of effort when testing GraphQL services by providing syntax highlighting, smart types, fields and query autocompletion tools, real-time error reporting and query inspecting.<\/p>\n\n\n\n<p>Again, in the <code>Startup<\/code> class, make the following changes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public const string GraphQlPath = \"\/graphql\";\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env)\n{\n    \/\/ ...\n    app.UseGraphiQl(GraphQlPath);\n}<\/pre>\n\n\n\n<p>Again, make sure to import the proper class at the beginning of the <code>Startup<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphiQl;<\/pre>\n\n\n\n<p>This will define in what endpoint GraphiQL UI will be available.<\/p>\n\n\n\n<p>Secondly, in order for this path be recognized as the official ruler of all GraphQL requests, you need to create a controller to manage the schema, variables and arguments. So, create the following class inside the <em>Controllers<\/em> folder:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL;\nnamespace GraphQL_SimpleTalk.Controllers\n{\n    public class GraphQlQuery\n    {\n        public string OperationName { get; set; }\n        public string NamedQuery { get; set; }\n        public string Query { get; set; }\n        public Inputs Variables { get; set; }\n    }\n}<\/pre>\n\n\n\n<p>This represents what a GraphQL query is. It\u2019s kind of a limitation of the library still, since they hadn\u2019t included this inside the graphql-dotnet. Then, create the following controller to handle all the operations:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL;\nusing GraphQL.Types;\nusing GraphQL_SimpleTalk.Queries;\nusing GraphQL_SimpleTalk.Services;\nusing Microsoft.AspNetCore.Mvc;\nusing System.Threading.Tasks;\nnamespace GraphQL_SimpleTalk.Controllers\n{\n    [Route(Startup.GraphQlPath)]\n    public class GraphQlController : Controller\n    {\n        readonly BlogService blogService;\n        public GraphQlController(BlogService blogService)\n        {\n            this.blogService = blogService;\n        }\n        [HttpPost]\n        public async Task&lt;IActionResult&gt; Post([FromBody] GraphQlQuery query)\n        {\n            var schema = new Schema { Query = new AuthorQuery(blogService) };\n            var result = await new DocumentExecuter().ExecuteAsync(x =&gt;\n            {\n                x.Schema = schema;\n                x.Query = query.Query;\n                x.Inputs = query.Variables;\n            });\n            if (result.Errors?.Count &gt; 0)\n            {\n                return BadRequest();\n            }\n            return Ok(result);\n        }\n    }\n}<\/pre>\n\n\n\n<p>This post method is important to summarize all the GraphQL schemas of your application in one place. Here, you have already referenced the <code>AuthorQuery<\/code> object, even though it doesn\u2019t exist yet. The <code>DocumentExecuter<\/code> is responsible for the GraphQL query execution, sending the schema, the query itself and the variables as arguments.<\/p>\n\n\n\n<p>Now, you must define what type of objects you\u2019re going to query. This example gets each of the author\u2019s data, the main query will be <code>AuthorQuery<\/code>. This will be the place to store each REST endpoint respective as a same-query operation.<\/p>\n\n\n\n<p>To understand it better, take a look at how the final GraphQL query will look (the same we\u2019ll use to test things in GraphiQL) :<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">query GetBlogData($id: Int!) {\n  author(id: $id) {\n    id\n    name\n  }\n  posts(id: $id) {\n    author {\n      bio\n    }\n    categories\n    comments {\n      description\n      count\n      url\n    }\n  }\n  socials(id: $id) {\n    nickName\n    type\n  }\n}<\/pre>\n\n\n\n<p>The first thing to notice is the parameter this query requires: the author\u2019s id. It is going to be used for each individual operation (author, posts and socials ones) as a query argument (yes, GraphQL also allows sending arguments) that\u2019ll define which records will be returned.<\/p>\n\n\n\n<p>The &#8220;!&#8221; sign says that this parameter is required, otherwise the query won\u2019t work.<\/p>\n\n\n\n<p>Lastly, see that you\u2019re only fetching the data from each object, to demonstrate that with GraphQL, you are the owner of the server\u2019s responses, that is, you only get what you really want.<\/p>\n\n\n\n<p>In graphql-dotnet, each query field (in this case: <code>author<\/code>, <code>posts<\/code> and <code>socials<\/code>) must be represented as a <code>GraphQL.Types.ObjectGraphType<\/code> in order to encapsulate each subfield definitions. Start with the <code>AuthorType<\/code> by creating the class in a new <em>Queries\\Types<\/em> folder:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL.Types;\nusing GraphQL_SimpleTalk.Entities;\nnamespace GraphQL_SimpleTalk.Queries.Types\n{\n    public class AuthorType : ObjectGraphType&lt;Author&gt;\n    {\n        public AuthorType()\n        {\n            Field(x =&gt; x.Id).Description(\"Id of an author\");\n            Field(x =&gt; x.Name).Description(\"Name of an author\");\n            Field(x =&gt; x.Bio).Description(\"Bio description of an author\");\n            Field(x =&gt; x.ImgUrl).Description(\"Url of an author's profile picture\");\n            Field(x =&gt; x.ProfileUrl).Description(\"Link of an author's profile\");\n        }\n    }\n}<\/pre>\n\n\n\n<p>The <code>ObjectGraphType<\/code> must receive a generic argument of the class this <code>GraphType<\/code> will configure. It\u2019s strictly necessary that you define here each one you want to be exposed by the GraphQL query mechanism. You\u2019re also setting the description in this type for you to notice how it appears in the final documentation in the GraphiQL interface.<\/p>\n\n\n\n<p>It\u2019s important to notice that for all the primitive types (string, int, etc.), you don\u2019t need to do anything other than referencing the field at <code>Field<\/code> \u2018s method. For types that you have created, you\u2019re obligated to say which <code>ObjectGraphType<\/code> is the one managing this specific subtype. Just like you see in the next <code>SocialNetworkType<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL.Types;\nusing GraphQL_SimpleTalk.Entities;\nnamespace GraphQL_SimpleTalk.Queries.Types\n{\n    public class SocialNetworkType : ObjectGraphType&lt;SocialNetwork&gt;\n    {\n        public SocialNetworkType()\n        {\n            Field(x =&gt; x.NickName);\n            Field&lt;EnumerationGraphType&lt;SNType&gt;&gt;(\"type\");\n            Field(x =&gt; x.Url);\n            Field&lt;AuthorType&gt;(\"author\");\n        }\n    }\n}<\/pre>\n\n\n\n<p>It\u2019s the same connotation and syntax, except for the <code>SNType<\/code> type (it will be created in the sequence). The <code>EnumerationGraphType<\/code> represents the default <code>GraphType<\/code> handler for enums in graphql-dotnet. The generic class must be provided subsequently along with the exact type name as a string. When it comes to the types, like the <code>author<\/code>, the <code>AuthorType<\/code> itself is enough.<\/p>\n\n\n\n<p>Add the rest of the types.<\/p>\n\n\n\n<p>The <code>SNTypeType<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL.Types;\nusing GraphQL_SimpleTalk.Entities;\nnamespace GraphQL_SimpleTalk.Queries.Types\n{\n    public class SNTypeType : EnumerationGraphType&lt;SNType&gt;\n    {\n        public SNTypeType()\n        {\n            Name = \"SNTypeType\";\n        }\n    }\n}<\/pre>\n\n\n\n<p>The <code>CommentType<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL.Types;\nusing GraphQL_SimpleTalk.Entities;\nnamespace GraphQL_SimpleTalk.Queries.Types\n{\n    public class CommentType : ObjectGraphType&lt;Comment&gt;\n    {\n        public CommentType()\n        {\n            Field(x =&gt; x.Count);\n            Field(x =&gt; x.Description);\n            Field(x =&gt; x.Url);\n        }\n    }\n}<\/pre>\n\n\n\n<p>The <code>RatingType<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL.Types;\nusing GraphQL_SimpleTalk.Entities;\nnamespace GraphQL_SimpleTalk.Queries.Types\n{\n    public class RatingType : ObjectGraphType&lt;Rating&gt;\n    {\n        public RatingType()\n        {\n            Field(x =&gt; x.Count);\n            Field(x =&gt; x.Percent);\n        }\n    }\n}<\/pre>\n\n\n\n<p>The <code>PostType<\/code> class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL.Types;\nusing GraphQL_SimpleTalk.Entities;\nnamespace GraphQL_SimpleTalk.Queries.Types\n{\n    public class PostType : ObjectGraphType&lt;Post&gt;\n    {\n        public PostType()\n        {\n            Field(x =&gt; x.Id);\n            Field(x =&gt; x.Title);\n            Field(x =&gt; x.Url);\n            Field(x =&gt; x.Date);\n            Field(x =&gt; x.Description);\n            Field&lt;AuthorType&gt;(\"author\");\n            Field&lt;RatingType&gt;(\"rating\");\n            Field&lt;ListGraphType&lt;CommentType&gt;&gt;(\"comments\");\n            Field(x =&gt; x.Categories, nullable: true);\n        }\n    }\n}<\/pre>\n\n\n\n<p>For lists and arrays, in addition, you must use <code>ListGraphType<\/code> as the default handler. Notice, too, that the <code>Categories<\/code> field was defined as non-nullable, another possible config you\u2019re going to use for testing.<\/p>\n\n\n\n<p>Finally, create the <code>AuthorQuery<\/code> in the <em>Queries<\/em> folder. Even being an <code>ObjectGraphType<\/code> too, this object is the most important one, since is here where the schema is defined, as well as the resolvers you\u2019ve seen before. There will be three fields: <code>author<\/code>, <code>posts<\/code>, and <code>socials<\/code>; each of them going through a different service method (which could possibly be another remote microservice, lambda or even data source) to fetch the data. See below the code:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using GraphQL.Types;\nusing GraphQL_SimpleTalk.Services;\nusing GraphQL_SimpleTalk.Queries.Types;\nnamespace GraphQL_SimpleTalk.Queries\n{\n    public class AuthorQuery : ObjectGraphType\n    {\n        public AuthorQuery(BlogService blogService)\n        {\n            Field&lt;AuthorType&gt;(\n                name: \"author\",\n                arguments: new QueryArguments(new QueryArgument&lt;IntGraphType&gt; { Name = \"id\" }),\n                resolve: context =&gt;\n                {\n                    var id = context.GetArgument&lt;int&gt;(\"id\");\n                    return blogService.GetAuthorById(id);\n                }\n            );\n            Field&lt;ListGraphType&lt;PostType&gt;&gt;(\n                name: \"posts\",\n                arguments: new QueryArguments(new QueryArgument&lt;IntGraphType&gt; { Name = \"id\" }),\n                resolve: context =&gt;\n                {\n                    var id = context.GetArgument&lt;int&gt;(\"id\");\n                    return blogService.GetPostsByAuthor(id);\n                }\n            );\n            Field&lt;ListGraphType&lt;SocialNetworkType&gt;&gt;(\n                name: \"socials\",\n                arguments: new QueryArguments(new QueryArgument&lt;IntGraphType&gt; { Name = \"id\" }),\n                resolve: context =&gt;\n                {\n                    var id = context.GetArgument&lt;int&gt;(\"id\");\n                    return blogService.GetSNsByAuthor(id);\n                }\n            );\n        }\n    }\n}<\/pre>\n\n\n\n<p>The first important impression is the new arguments field defining a new <code>QueryArguments<\/code> for the id of an author represented as an <code>IntGraphType<\/code>.<\/p>\n\n\n\n<p>The code snippet <code>var id = context.GetArgument&lt;int&gt;(\"id\");<\/code> is responsible for retrieving this argument based on its previous definition. The rest are just simple service calls. Also, notice that for each different type of return, the right type of the field must be outlined (e.g. <code>ListGraphType<\/code>).<\/p>\n\n\n\n<p>It\u2019s up to you determine if the <code>posts<\/code> and <code>socials<\/code> come directly within the author. This way, you\u2019d implement all the searches inside of <code>author<\/code>\u2018s <code>resolve<\/code> parameter, however, you\u2019d also have to have the proper attributes into the <code>Author<\/code> entity and <code>AuthorType<\/code> graph type.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-graphiql\">GraphiQL<\/h2>\n\n\n\n<p>Time to test it! Start up the application again and access the URL: <a href=\"https:\/\/localhost:44360\/graphql\">https:\/\/localhost:44360\/graphql<\/a>. This is the screen that\u2019ll appear:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1521\" height=\"919\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-72.png\" alt=\"\" class=\"wp-image-82854\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n<div class=\"block-core-list\">\n<ol class=\"wp-block-list\">\n<li>The querying tool. In this box, you can type your GraphQL queries and it\u2019ll give hints about the schema, autocomplete (\u201cCtrl + Escape\u201d to trigger it), and validate the syntax;<\/li>\n\n\n\n<li>Button to run the queries;<\/li>\n\n\n\n<li>Button to prettify the code, indent;<\/li>\n\n\n\n<li>When clicked, show a side box with all the history of queries, even if you turn off the application;<\/li>\n\n\n\n<li>The box to add the query variables. They\u2019re useful when you need to parameterize the query itself with data that comes from unknown sources;<\/li>\n\n\n\n<li>Documentation explorer. Here, you can search for query objects, its fields, arguments, types, nullability, etc.<\/li>\n<\/ol>\n<\/div>\n\n\n<p>The last item deserves a bit more of attention because it can be truly helpful when you\u2019re accessing a GraphQL schema that you no nothing about. Have a look at the following screens:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"892\" height=\"914\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-73.png\" alt=\"\" class=\"wp-image-82855\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>It represents the navigation upon the <code>AuthorQuery<\/code> schema. You can see docs from the list of root types (the available queries), each type\u2019s fields (ant their respective declarations), to the arguments and even GraphQL inner types.<\/p>\n\n\n\n<p>In the third screen, specifically, if you click in <code>AuthorType<\/code> type, you\u2019ll see the following screen:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"440\" height=\"643\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-74.png\" alt=\"\" class=\"wp-image-82856\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Those are the descriptions you\u2019ve previously set at the <code>AuthorType<\/code> class. So, go ahead and customize your docs.<\/p>\n\n\n\n<p>To see how this works, add this query to the Query window:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">query GetBlogData($id: Int!) {\n  author(id: $id) {\n    id\n    name\n  }\n  posts(id: $id) {\n    author {\n      bio\n    }\n    categories\n    comments {\n      description\n      count\n      url\n    }\n  }\n  socials(id: $id) {\n    nickName\n    type\n  }\n}<\/pre>\n\n\n\n<p>You must also add the Query Variable:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n    \"id\":1\n}<\/pre>\n\n\n\n<p>Click the run button to try it out:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1670\" height=\"919\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/01\/word-image-75.png\" alt=\"\" class=\"wp-image-82857\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>That\u2019s the same query pointed out before. The only new thing here is the query variable <code>id<\/code> that\u2019s passed. The results, at the right side of the screen, are pretty much everything you\u2019ll receive from the server. If you don\u2019t need the <code>posts<\/code> or the <code>socials<\/code>, you don\u2019t have to add them to the query, and the resolver won\u2019t be called just the same way.<\/p>\n\n\n\n<p>The input variables for the query don\u2019t have to be, necessarily, primitive values. You can specify another type to the schema, like <code>AuthorType<\/code>, and ask the clients to send a full filled author to register in your application, for example. This communication can happen with either action method, whether it is a single GET or a registration POST like you have in REST.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-summary\">Summary<\/h2>\n\n\n\n<p>This article covered the main basics regarding GraphQL services exposure in ASP.NET applications. GraphQL is highly flexible and data-driven, which means that you can now focus you client development in the exact data you want to receive from the server, i.e., you\u2019re the owner of the data you want to get.<\/p>\n\n\n\n<p>In order to improve your skills, in addition to the <a href=\"https:\/\/github.com\/graphql-dotnet\/graphql-dotnet\">official graphql-dotnet docs<\/a>, graphql-dotnet also provides some <a href=\"https:\/\/github.com\/graphql-dotnet\/examples\">sample projects<\/a> with more configurations. Obviously, you can count on the <a href=\"https:\/\/github.com\/facebook\/graphql\">official Facebook\u2019s GraphQL specification<\/a> as well as the <a href=\"https:\/\/www.howtographql.com\">howtographql.com<\/a> popular learning courses arranged by and to the community. Best of studies!<\/p>\n\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs: Getting started with GraphQL in ASP .NET<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. What is the difference between GraphQL and REST?<\/h3>\n            <div class=\"faq-answer\">\n                <p>REST uses multiple endpoints (e.g., \/users, \/users\/1\/posts, \/users\/1\/settings), each returning a fixed data structure. GraphQL uses a single endpoint where the client specifies exactly what data it needs in a query. This eliminates over-fetching (getting more data than needed) and under-fetching (needing multiple requests to get all required data). GraphQL also provides a strongly-typed schema and built-in introspection, making APIs self-documenting.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. How do you set up GraphQL in an ASP.NET Core project?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Install the GraphQL NuGet packages, define your schema types (ObjectGraphType classes that map to your data models), create resolvers that fetch data for each field, register the schema and its dependencies in Startup.cs, and expose a single POST endpoint that accepts GraphQL query strings. Add GraphQL for an interactive query testing interface during development.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. What are resolvers in GraphQL?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Resolvers are functions that return data for specific fields in your GraphQL schema. Each field in a type can have its own resolver that determines how to fetch the data &#8211; from a database, an external API, a cache, or any other source. Resolvers let you compose data from multiple sources in a single query response, which is one of GraphQL\u2019s key advantages over REST.<\/p>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to implement GraphQL in ASP.NET with C#. Compares REST vs GraphQL architecture, covers schema types, queries, resolvers, and mutations with a working demo project.&hellip;<\/p>\n","protected":false},"author":323407,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[95509],"coauthors":[93894],"class_list":["post-82844","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-standardize"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82844","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/323407"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=82844"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82844\/revisions"}],"predecessor-version":[{"id":108993,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82844\/revisions\/108993"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=82844"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=82844"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=82844"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=82844"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}