{"id":52674,"date":"2024-07-11T10:05:00","date_gmt":"2024-07-11T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=52674"},"modified":"2024-07-15T13:02:22","modified_gmt":"2024-07-15T20:02:22","slug":"why-and-how-to-execute-graph-ql-queries-in-dotnet","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/why-and-how-to-execute-graph-ql-queries-in-dotnet\/","title":{"rendered":"Why and How to Execute GraphQL Queries in .NET"},"content":{"rendered":"<p>Most (if not all) projects are consuming APIs to get data, and there many ways to do it. One of the most popular ways is to use REST APIs. However, REST APIs have some limitations, such as over-fetching (forcing the client to load all properties even when only a few are needed for the UI). GraphQL is a great alternative to REST APIs because it allows you to request only the data you need, which can help reduce the amount of data transferred over the network and improve performance. It also allows you to request information coming from multiple resources in a single request, thus avoiding multiple &#8220;round trips&#8221; that can negatively impact performance and the user experience.<\/p>\n<p>In this post, I will show you how to query a GraphQL API in .NET using Strawberry Shake GraphQL client. With Strawberry Shake version 13 there are now 3 packages:<\/p>\n<ul>\n<li><strong>StrawberryShake.Server<\/strong>: For consoles or backend-to-backend.<\/li>\n<li><strong>StrawberryShake.Blazor<\/strong>: For Blazor projects, use this package in your project, and we pre-configured it to generate Razor components automatically and use a client-side store for reactive web applications.<\/li>\n<li><strong>StrawberryShake.Maui<\/strong>: For Maui projects.<\/li>\n<\/ul>\n<p>This post will familiarize you with GraphQL in a .NET application, and will provide you with context to better understand the Blazor and Maui implementations if you are using those technologies.<\/p>\n<h2>The API and the Database<\/h2>\n<p>For this post, I really want to focus on the GraphQL implementation. The sample is using a SQL Server instance paired with a GraphQL API genarated with Data API Builder both running locally in Docker containers &#8211; if you really want to follow along you can find the <a href=\"https:\/\/github.com\/FBoucher\/startrek-demo#database-and-apis-in-containers\">setup steps and T-SQL script in the repo<\/a>. But the important part is that this will work with any data source that you want to expose through GraphQL.<\/p>\n<p>You can also find the code for this post in the <a href=\"https:\/\/github.com\/fboucher\/startrek-demo\">startrek-demo<\/a> GitHub repo.<\/p>\n<h2>Let&#8217;s create the console application<\/h2>\n<p>In a terminal, execute the following command to create a new project, move into the new folder created, and add Strawberry Shake <strong>nuget<\/strong> package to the project.<\/p>\n<pre><code class=\"language-powershell\">dotnet new console -n GraphqlDemo \u00a0--use-program-main\ncd .\\startrekdemo\\\ndotnet add package StrawberryShake.Server<\/code><\/pre>\n<p>Strawberry Shake comes with tools to help improve your experience building a GraphQL client. You install tools in .NET projects by providing a manifest. Let&#8217;s create a dotnet-tools manifest and add the GraphQL tool locally. We will see what is created in a few steps.<\/p>\n<pre><code class=\"language-powershell\">dotnet new tool-manifest\ndotnet tool install StrawberryShake.Tools --local<\/code><\/pre>\n<p>In GraphQL, APIs are defined by a schema. This is similar to how OpenAPI is used to document REST endpoints. Like OpenAPI, you can use the schema to generate the code for .NET clients that are ready &#8220;out of the box&#8221; to consume their owned data. This is how Strawberry Shake will generate a client for us based on the schema. The Startrek GraphQL API is running locally, and accessible at <code>http:\/\/localhost:5000\/graphql<\/code>. To download the GraphQL schema, and generate the client code specifying the client name &#8220;StartrekClient&#8221;, run the following command:<\/p>\n<pre><code class=\"language-powershell\">dotnet graphql init http:\/\/localhost:5000\/graphql -n StartrekClient<\/code><\/pre>\n<p>It&#8217;s finally time to open the project and look at what we have&#8230; <\/p>\n<p>Note the generated files:<\/p>\n<ul>\n<li><code>.config\\dotnet-tools.json<\/code><\/li>\n<li><code>.graphqlrc.json<\/code> with our client&#8217;s name <strong>StartrekClient<\/strong><\/li>\n<li><code>schema.extensions.graphql<\/code><\/li>\n<li><code>schema.graphql<\/code><\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/07\/created_files.png\" alt=\"Created files\" \/><\/p>\n<h2>Adding a new query<\/h2>\n<p>In the current database I have 3 tables: Series, Character, and a relation table Series_Character. The schema is as follows:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/07\/startrek-3tables.svg\" alt=\"Startrek Database Schema\" \/><\/p>\n<p>With a REST API, the typical design is to provide an endpoint with a list of series and another with a list of characters in the series. A client would need to make multiple requests in order to get the characters for multiple series. GraphQL enables you to retrieve all of this data in a single call! <a href=\"https:\/\/chillicream.com\/products\/bananacakepop\">Banana Cake Pop<\/a> is a nice GraphQL IDE for Developers, a bit like Swagger for REST APIs. You can learn more about it and Data API Builder in this session <a href=\"https:\/\/www.youtube.com\/watch?v=A1H1kVPHs3w\">The most minimal API code of all&#8230; none<\/a> that I did with Jerry Nixon during Developer .NET Day .<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/07\/bananacakepop.png\" alt=\"Banana Cake Pop Interface\" \/><\/p>\n<p>To add a new query, create a new file <code>getCharacterbySeries.graphql<\/code> in the root of the project. Here is a query that will return a list of series with the characters for each series.<\/p>\n<pre><code class=\"language-graphql\">query getCharacterbySeries{\n    series {\n        items {\n            Name\n            character {\n                items {\n                    Name\n                }\n            }\n        }\n    }\n}<\/code><\/pre>\n<p>The syntax looks similar to JSON, but is in fact specific to GraphQL. Looking at the tables diagram, notice that the query doesn&#8217;t contain the property <code>StartDate<\/code> from the <code>Character<\/code> table. With bigger tables, this can be a huge performance gain, as the client avoid over-fetching data that isn&#8217;t used.<\/p>\n<p>After compiling the project <code>dotnet build<\/code>, you can see the generated the GraphQL client in <code>obj\\Debug\\net8.0\\berry\\GraphqlDemo.Client.cs<\/code>. This is one of the changes that Strawberry Shake made in version 13. The generated code is now in a folder called <code>berry<\/code> and not in the <code>Generated<\/code> folder as before.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/07\/generated_code.png\" alt=\"Generated Code\" \/><\/p>\n<h2>Using the generated GraphQL client<\/h2>\n<p>Open the file <code>Program.cs<\/code> file. Add the using for dependency injection at the top of the file.<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.Extensions.DependencyInjection;<\/code><\/pre>\n<p>Let&#8217;s modify <code>Main<\/code> with the following code to create an instance of the StartrekClient (aka the GraphQL client).<\/p>\n<pre><code class=\"language-csharp\">static async Task Main(string[] args)\n{\n    var servicesCollection = new ServiceCollection();\n    servicesCollection.AddStartrekClient().ConfigureHttpClient(client =&gt;\n    {\n        client.BaseAddress = new Uri(\"http:\/\/localhost:5000\/graphql\");\n    });\n\n    var services = servicesCollection.BuildServiceProvider();\n    var client = services.GetRequiredService&lt;IStartrekClient&gt;();\n\n    \/\/ Execute the query GetCharacterbySeries\n    var result = await client.GetCharacterbySeries.ExecuteAsync();\n\n    \/\/ Loop through the series and characters to display the results\n    foreach (var tvShow in result.Data.Series.Items)\n    {\n        Console.WriteLine($\"Series: {tvShow.Name}\");\n        foreach (var character in tvShow.Character.Items)\n        {\n            Console.WriteLine($\" . {character.Name}\");\n        }\n    }\n}\n<\/code><\/pre>\n<p>The few last lines of <code>Main<\/code> are looping through query results and display the information. Executing the code <code>dotnet run<\/code>, will write a list of series with the characters for each series.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/07\/graphql_result.png\" alt=\"graphql query result\" \/><\/p>\n<h2>What&#8217;s Next?<\/h2>\n<p>In this post, I showed you how to query a GraphQL API in .NET using Strawberry Shake from a console application. I hope you found this post helpful and that you are now ready to start using GraphQL in your .NET projects. In the next post, let&#8217;s explore how we can execute GraphQL queries in a Blazor project and display the result using the new QuickGrid.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post shows how to query a GraphQL API in .NET using Strawberry Shake from a console application<\/p>\n","protected":false},"author":149092,"featured_media":52740,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,756,7259],"tags":[4,7852,7853],"class_list":["post-52674","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-csharp","category-sql-server","tag-net","tag-graphql","tag-strawberryshake"],"acf":[],"blog_post_summary":"<p>This post shows how to query a GraphQL API in .NET using Strawberry Shake from a console application<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/52674","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/149092"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=52674"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/52674\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/52740"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=52674"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=52674"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=52674"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}