Compiled Experience Windows Platform Development http://compiledexperience.com en Sun, 08 Sep 2019 23:53:33 +0000 Sun, 08 Sep 2019 23:53:33 +0000 Speaking at .NET Conf 2019 <p>I’m pleased to announce that I’ll be speaking in a few weeks at the Microsoft virtual conference <a href="https://www.dotnetconf.net/">.NET Conf</a>! This looks like it’ll be a great conference that covers a wide range of subjects and also includes the launch of .NET Core 3.0.</p> <p>Personally I’ll be speaking on <em>An Introduction to GraphQL in .NET Core</em>, I’ve found a majority of GraphQL 101 style talks are heavily focussed around the Node ecosystem. In fact a lot of discussions around the limitations of a specifics such as schema stitching are more about certainl implementations rather than the appoach in general (but that’s another rant). Given this I’m very keen to be able to start with an introduction to using GraphQl with examples of building a service using .NET Core and in particular the <a href="https://github.com/ChilliCream/hotchocolate">Hot Chocolate</a> library.</p> <p>Check out the <a href="https://www.dotnetconf.net/agenda">agenda</a> and see what piques your interest.</p> Mon, 09 Sep 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/dotnetconf-2019 http://compiledexperience.com/blog/posts/dotnetconf-2019 nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql Approval Tests <p>Approval Tests or Snapshot Tests are in my opinion a vital part of the testing ecosystem that can service a number of uses cases. In this post I’ll introduce the concepts and discuss some of the scenarios we may want to employ them to best effect.</p> <h2 id="what-are-approval-tests">What are approval tests?</h2> <p>Approval tests work by creating an output that needs human approval / verification. This could be because of a number of reasons:</p> <ul> <li>The output is visual such as a screenshot.</li> <li>The output is too large for regular unit testing assertions (a complex object graph etc.).</li> <li>The output has no way to programmatically defined.</li> </ul> <p>Once the initial output has been defined and “approved” then as long as the test provides consistent output then the test will continue to pass. Once the test provides output that is different to the approved output then the test will fail. The developer then has two choices:</p> <ol> <li>If the change in the output was unintended then fix the bug that’s causing the change in the output.</li> <li>“Approve” the new output as the baseline for future tests.</li> </ol> <p>I’ve been very vague here about “output” intentionally because that output can be anything you want really, as long as it can be compared to another copy in a consistent manner.</p> <h2 id="when-should-i-use-approval-tests">When should I use approval tests?</h2> <p>Here are some scenarios where we use approval tests at <a href="https://pushpay.com">Pushpay</a>.</p> <h3 id="website-visuals">Website Visuals</h3> <p>We use an automated testing process that takes screenshots (using headless Chrome) of most pages in our web applications with static data. If the page has changed for any reason then the test fails. If that change is intended the developer can simply mark the new visual as approved and carry on, otherwise it gives a clear indidication that the changes they’re testing are having unintended consequences on pages they didn’t attend.</p> <h3 id="api-contracts">API Contracts</h3> <p>We use the SDL of GraphQL API’s and Swagger for the REST API’s as the output for an approval test. What this means is that any change that results in the change to the public API contract will result in a failed test. We want to be very deliberate in any changes we make in the contracts we expose to other teams and this guards against unintended changes. It also forces the developer to think very closely about the contract as they approve it.</p> <h3 id="exceptions-to-the-rule">Exceptions to the rule</h3> <p>We may have a conventions or policies that will almost always have exceptions. An example of this are our feature flags, ideally our Sandbox and Production environments should be very similar in terms of which flags are on. We can have an approval test where the output is the list of all flags where the state is different between environments, this way we can capture and approve exceptions to our rule and ensure that any of these exceptions are intentional and approved.</p> <h2 id="approval-tests-in-net">Approval Tests in .NET</h2> <p>Some good frameworks I’ve used for approval tests in .NET are <a href="https://github.com/approvals/ApprovalTests.Net">Approval Tests.NET</a> and <a href="https://github.com/SwissLife-OSS/snapshooter">Snapshooter</a>.</p> <h2 id="summary">Summary</h2> <p>I hope you can see from the examples above that approval tests fill a very valuable niche where the output of the test requires human intelligence to assert corrections. They can capture impossible to assert rules as well as exceptions to the rules. They can help to ensure that changes to critical parts of your system such as the API and the visuals are intentional and approved.</p> Tue, 30 Jul 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/approval-tests http://compiledexperience.com/blog/posts/approval-tests nigel.sampson@compiledexperience.com (Nigel Sampson) csharp Automatically validate arguments in GraphQL <p>In my last post on <a href="/blog/posts/grapql-validation-metadata">Exposing Validation Metadata in GraphQL</a> I showed how we can expose validation metadata from the server to the client in order to have to only define our validation rules once. In this post I’ll show how to autoamically enforce those validation rules on the server.</p> <p>Having validation rules defined doesn’t mean much if we don’t enforce them. In when using MVC this was done through the <code class="highlighter-rouge">ModelState</code> property on the <code class="highlighter-rouge">Controller</code>. You’d regularly see code in the following pattern in your controllers.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">IActionResult</span> <span class="nf">CreatePerson</span><span class="p">(</span><span class="n">CreatePersonInput</span> <span class="n">input</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(!</span><span class="n">ModelState</span><span class="p">.</span><span class="n">IsValid</span><span class="p">)</span> <span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">input</span><span class="p">);</span> <span class="p">...</span> <span class="p">}</span> </code></pre></div></div> <p>There’s nothing wrong with this code, but one thing that did bug me was it didn’t feel like the “pit of success”.</p> <blockquote> <p>The Pit of Success: in stark contrast to a summit, a peak, or a journey across a desert to find victory through many trials and surprises, we want our customers to simply fall into winning practices by using our platform and frameworks. To the extent that we make it easy to get into trouble we fail.</p> </blockquote> <p>In this case it’s too easy to forget to add those lines to your contoller and leave validation compltely off your endpoint. We can solve this in MVC by using filters to enforece validation on all our <code class="highlighter-rouge">POST</code> requests.</p> <h2 id="graphql-middleware">GraphQL Middleware</h2> <p>Middleware is a very overloaded term when it comes to software development, within the context of frameworks it typically refers to a pluggable pipeline that an operation moves through. What gets confusing is that each framework typically has it’s own notion of middleware which can make them confusing when discussing them.</p> <p>An example of this is that .NET Core has a concept of middleware for any <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware">incoming requests</a>, in fact <a href="https://hotchocolate.io/">Hot Chocolate</a> the GraphQL framework we’re using is implemented as a piece of .NET Core middleware where it examines requests and if it determines that it’s a GraphQL query will execute it.</p> <p><a href="https://hotchocolate.io/">Hot Chocolate</a> also has it’s own <a href="https://hotchocolate.io/docs/middleware">concept of middleware</a>, in fact it has three.</p> <ul> <li>Query Middleware</li> <li>Field Middleware</li> <li>Directive Middleware</li> </ul> <p>These are all similar in concept in that these are a pipeline that is executed as the GraphQL query / mutation is executed. The difference is simply the scope of the middleware and when it’s executed. Let’s examine each in turn and in the context of enforcing validation.</p> <h3 id="query-middleware">Query Middleware</h3> <p>This middleware is executed once per query / mutation and roughly akin to the MVC filters discussed above. For an MVC system this would be the ideal place for validation, but a GraphQL query can have any number of fields with any number of arguments. Implementing validation in query level middleware would involve having to walk to the document to find all the values and so isn’t our best candidate.</p> <h3 id="field-middleware">Field Middleware</h3> <p>This middleware is executed whenever the field the middleware is applied to resolved. This gives us a wide range of options. If we apply the field middleware to the schema directly:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SchemaBuilder</span><span class="p">.</span><span class="nf">New</span><span class="p">()</span> <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">ValidateInputMiddleware</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">Create</span><span class="p">();</span> </code></pre></div></div> <p>then this middleware will execute for every single field on every single request. This may be desirable in some scenarios but for ours is probably overkill. However if we’re defining our schema in a code first manner we can apply middleware to just the fields we care about:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">descriptor</span><span class="p">.</span><span class="nf">Field</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="nf">CreatePerson</span><span class="p">(</span><span class="k">default</span><span class="p">))</span> <span class="p">.</span><span class="nf">Argument</span><span class="p">(</span><span class="s">"input"</span><span class="p">,</span> <span class="n">a</span> <span class="p">=&gt;</span> <span class="n">a</span><span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">CreatePersonInputType</span><span class="p">&gt;&gt;())</span> <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">ValidateInputMiddleware</span><span class="p">&gt;();</span> </code></pre></div></div> <p>This middleware will only execute when the <code class="highlighter-rouge">createPerson</code> mutation is executed which is very limited in scope, but here we’re back to having to remember to apply it to the fields we want validation on. The former approach is overly broad but automatic, the latter exactly brroad enough but not automatic.</p> <h3 id="directive-middleware">Directive Middleware</h3> <p>The latter approach above use a code first schema definition to apply a piece of middleware to only specifc fields. If we’re using a schema first approach then how can we do something similar? We can leverage directives, I think of these in the same way as C# attributes, pieces of metadata attached to our queries and schema. In <a href="https://hotchocolate.io/">Hot Chocolate</a> directives can apply middleware. If we define one that looks like:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ValidateInputDirective</span> <span class="p">{</span> <span class="p">}</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">ValidateInputDirectiveType</span> <span class="p">:</span> <span class="n">DirectiveType</span><span class="p">&lt;</span><span class="n">ValidateInputDirective</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IDirectiveTypeDescriptor</span><span class="p">&lt;</span><span class="n">ValidateInputDirective</span><span class="p">&gt;</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="k">base</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">descriptor</span><span class="p">);</span> <span class="n">descriptor</span> <span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="s">"validateInput"</span><span class="p">)</span> <span class="p">.</span><span class="nf">Location</span><span class="p">(</span><span class="n">DirectiveLocation</span><span class="p">.</span><span class="n">FieldDefinition</span><span class="p">)</span> <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">ValidateInputMiddleware</span><span class="p">&gt;();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>With this defined we can now apply the directive in our schema.</p> <div class="language-graphql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span><span class="w"> </span><span class="n">Mutation</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">createPerson</span><span class="p">(</span><span class="n">input</span><span class="p">:</span><span class="w"> </span><span class="n">CreatePersonInput</span><span class="p">!)</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Person</span><span class="w"> </span><span class="err">@</span><span class="n">validateInput</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h2 id="validate-input-middleware">Validate Input Middleware</h2> <p>So now we have three approaches to apply your middleware depending on the how specific or broad you want to apply it, what does the middleware itself look like? In fact it’s pretty simple.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ValidateInputMiddleware</span> <span class="p">{</span> <span class="k">private</span> <span class="k">readonly</span> <span class="n">FieldDelegate</span> <span class="n">_next</span><span class="p">;</span> <span class="k">public</span> <span class="nf">ValidateInputMiddleware</span><span class="p">(</span><span class="n">FieldDelegate</span> <span class="n">next</span><span class="p">)</span> <span class="p">{</span> <span class="n">_next</span> <span class="p">=</span> <span class="n">next</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Invoke</span><span class="p">(</span><span class="n">IMiddlewareContext</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">FieldSelection</span><span class="p">.</span><span class="n">Arguments</span><span class="p">.</span><span class="n">Count</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span> <span class="p">{</span> <span class="k">await</span> <span class="nf">_next</span><span class="p">(</span><span class="n">context</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">var</span> <span class="n">errors</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">FieldSelection</span><span class="p">.</span><span class="n">Arguments</span> <span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">a</span> <span class="p">=&gt;</span> <span class="n">context</span><span class="p">.</span><span class="n">Argument</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;(</span><span class="n">a</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">Value</span><span class="p">))</span> <span class="p">.</span><span class="nf">SelectMany</span><span class="p">(</span><span class="n">ValidateObject</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">errors</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span> <span class="p">{</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">error</span> <span class="k">in</span> <span class="n">errors</span><span class="p">)</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="nf">ReportError</span><span class="p">(</span><span class="n">ErrorBuilder</span><span class="p">.</span><span class="nf">New</span><span class="p">()</span> <span class="p">.</span><span class="nf">SetCode</span><span class="p">(</span><span class="s">"error.validation"</span><span class="p">)</span> <span class="p">.</span><span class="nf">SetMessage</span><span class="p">(</span><span class="n">error</span><span class="p">.</span><span class="n">ErrorMessage</span><span class="p">)</span> <span class="p">.</span><span class="nf">SetExtension</span><span class="p">(</span><span class="s">"memberNames"</span><span class="p">,</span> <span class="n">error</span><span class="p">.</span><span class="n">MemberNames</span><span class="p">)</span> <span class="p">.</span><span class="nf">AddLocation</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">FieldSelection</span><span class="p">.</span><span class="n">Location</span><span class="p">.</span><span class="n">Line</span><span class="p">,</span> <span class="n">context</span><span class="p">.</span><span class="n">FieldSelection</span><span class="p">.</span><span class="n">Location</span><span class="p">.</span><span class="n">Column</span><span class="p">)</span> <span class="p">.</span><span class="nf">SetPath</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">Path</span><span class="p">)</span> <span class="p">.</span><span class="nf">Build</span><span class="p">());</span> <span class="p">}</span> <span class="n">context</span><span class="p">.</span><span class="n">Result</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">await</span> <span class="nf">_next</span><span class="p">(</span><span class="n">context</span><span class="p">);</span> <span class="p">}</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ValidationResult</span><span class="p">&gt;</span> <span class="nf">ValidateObject</span><span class="p">(</span><span class="kt">object</span> <span class="n">argument</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">results</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">ValidationResult</span><span class="p">&gt;();</span> <span class="n">Validator</span><span class="p">.</span><span class="nf">TryValidateObject</span><span class="p">(</span><span class="n">argument</span><span class="p">,</span> <span class="k">new</span> <span class="nf">ValidationContext</span><span class="p">(</span><span class="n">argument</span><span class="p">),</span> <span class="n">results</span><span class="p">,</span> <span class="n">validateAllProperties</span><span class="p">:</span> <span class="k">true</span><span class="p">);</span> <span class="k">return</span> <span class="n">results</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>This code is for a field level middleware (regardless of whether it’s applied at the schema for field level), if you want to use this as directive middleware simply change the type of the Invoke parmeter from <code class="highlighter-rouge">IMiddlewareContext</code> to <code class="highlighter-rouge">IDirectiveContext</code>.</p> <p>Walking through the code isn’t overly complicated, we get the values for all the arguments of the field and validate them combinng the results into a single list. If there are any errors then we report them as errors, set the result of the field to be null, otherwise we we call the next piece of middleware in the chain. This last step is important because it means that the mutation will never be called if there are validation errors.</p> <h2 id="conclusion">Conclusion</h2> <p>In this post we looking at middleware in the context of a GraphQL request and how we can use it to provide automatic validation of arguments. We can see how the middleware can determine to terminate the pipeline to ensure that under the correct circumstances the field is never resolved.</p> Mon, 08 Jul 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/graphql-validate-arguments http://compiledexperience.com/blog/posts/graphql-validate-arguments nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql Exposing Validation Metadata in GraphQL <p>When we do input validation in our applications we want them on both the client and server for a couple of key reasons:</p> <ol> <li>Validation on the client introduces better opporutunities for a richer user experience.</li> <li>We validate on the server as well because we can’t trust the client.</li> </ol> <p>One other goal we have is to only define our validation rules once, if we have to define our client and server validation in separate locations in our code we run the risk of one location not being updated and having a drift between client and server.</p> <h3 id="how-is-this-done-in-net">How is this done in .NET?</h3> <p>ASP.NET has the a <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.modelmetadata?view=aspnetcore-2.2"><code class="highlighter-rouge">ModelMetadata</code></a> system that is highly extensible via a provider model and enables a way to view the validation rules. The out of the provider uses the <code class="highlighter-rouge">System.ComponentModel.DataAnnotations</code> attributes for validation definition giving us something like:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">CreatePersonInput</span> <span class="p">{</span> <span class="p">[</span><span class="nf">StringLength</span><span class="p">(</span><span class="m">100</span><span class="p">)]</span> <span class="k">public</span> <span class="kt">string</span> <span class="n">FirstName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;}</span> <span class="p">[</span><span class="n">Required</span><span class="p">]</span> <span class="p">[</span><span class="nf">StringLength</span><span class="p">(</span><span class="m">100</span><span class="p">)]</span> <span class="k">public</span> <span class="kt">string</span> <span class="n">LastName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;}</span> <span class="p">}</span> </code></pre></div></div> <p>The out of the box Razor view system can then use the model metadata to write these validation rules into the html which can then be used the a front end validation framework such as <code class="highlighter-rouge">jquery-validation-unobtrusive</code>. You can read more about the whole system in <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-2.2">Model validation in ASP.NET Core MVC and Razor Pages</a>.</p> <h3 id="the-graphql-approach">The GraphQL approach</h3> <p>How can reproduce parts of this approach in a GraphQL based system? Our goal is to define validation rules on the input objects that are arguments to our queries and mutations and then have a way to expose those rules to a client consuming our API.</p> <p>The <a href="https://graphql.github.io/graphql-spec/June2018/">GraphQL specification</a> doesn’t have way to define validation rules, but it does have the concept of <a href="https://graphql.github.io/learn/queries/#directives">directives</a> which fill much the same space as attributes do in C#. They’re a mechanism to annotate a GraphQL schema with metadata that can be consumed by the server, client or tool such as a code generator.</p> <p>For the example above we may want to have something like the following in our schema:</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>input CreatePersonInput { firstName: String @stringLength(maximumLength: 100) lastName: String! @required @stringLength(maximumLength: 100) } </code></pre></div></div> <blockquote> <p>I’ve wrapped the directives onto the lines after the field, this is just for readaiblity, they can all be on the same line (space separated).</p> </blockquote> <blockquote> <p>It’s also arguable that the fact that <code class="highlighter-rouge">lastName</code> is defined as not being nullable and required is redundant, but I’ve included it here to match up with validation attributes.</p> </blockquote> <h3 id="defining-our-directives">Defining our directives</h3> <p>The first step is create our directives and register them with our schema. I’ve deliberately kept these simple but you can imagine extending them with custom validation messages and the like. We’re building on top of the <a href="https://hotchocolate.io/">Hot Chocolate</a> GraphQL library.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">RequiredDirective</span> <span class="p">{</span> <span class="p">}</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">RequiredDirectiveType</span> <span class="p">:</span> <span class="n">DirectiveType</span><span class="p">&lt;</span><span class="n">RequiredDirective</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IDirectiveTypeDescriptor</span><span class="p">&lt;</span><span class="n">RequiredDirective</span><span class="p">&gt;</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="k">base</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">descriptor</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="s">"required"</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Location</span><span class="p">(</span><span class="n">DirectiveLocation</span><span class="p">.</span><span class="n">InputFieldDefinition</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">StringLengthDirective</span> <span class="p">{</span> <span class="k">public</span> <span class="kt">int</span> <span class="n">MaximumLength</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">StringLengthDirectiveType</span> <span class="p">:</span> <span class="n">DirectiveType</span><span class="p">&lt;</span><span class="n">StringLengthDirective</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IDirectiveTypeDescriptor</span><span class="p">&lt;</span><span class="n">StringLengthDirective</span><span class="p">&gt;</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="k">base</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">descriptor</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="s">"stringLength"</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Location</span><span class="p">(</span><span class="n">DirectiveLocation</span><span class="p">.</span><span class="n">InputFieldDefinition</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Argument</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">MaximumLength</span><span class="p">)</span> <span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="s">"maximumLength"</span><span class="p">)</span> <span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">IntType</span><span class="p">&gt;&gt;();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">schema</span> <span class="p">=</span> <span class="n">SchemaBuilder</span><span class="p">.</span><span class="nf">New</span><span class="p">()</span> <span class="p">.</span><span class="n">RegisterDirective</span><span class="p">&lt;</span><span class="n">RequiredDirectiveType</span><span class="p">&gt;()</span> <span class="p">.</span><span class="n">RegisterDirective</span><span class="p">&lt;</span><span class="n">StringLengthDirectiveType</span><span class="p">&gt;()</span> <span class="p">.</span><span class="nf">Create</span><span class="p">();</span> </code></pre></div></div> <h3 id="code-first-schema">Code first schema</h3> <p>In a code first schema approach we would expect to see something like the following for our <code class="highlighter-rouge">CreatePersonInput</code>, this is just enough configuration to override the default nullable string for <code class="highlighter-rouge">LastName</code>.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">CreatePersonInputType</span> <span class="p">:</span> <span class="n">InputObjectType</span><span class="p">&lt;</span><span class="n">CreatePersonInput</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IInputObjectTypeDescriptor</span><span class="p">&lt;</span><span class="n">CreateCommunityMemberInput</span><span class="p">&gt;</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="k">base</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">descriptor</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Field</span><span class="p">(</span><span class="n">c</span> <span class="p">=&gt;</span> <span class="n">c</span><span class="p">.</span><span class="n">LastName</span><span class="p">)</span> <span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">StringType</span><span class="p">&gt;&gt;();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>We could then get the schema outcome by adding the appropriate directives here</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Field</span><span class="p">(</span><span class="n">c</span> <span class="p">=&gt;</span> <span class="n">c</span><span class="p">.</span><span class="n">FirstName</span><span class="p">)</span> <span class="p">.</span><span class="nf">Directive</span><span class="p">(</span><span class="k">new</span> <span class="n">StringLengthDirective</span> <span class="p">{</span> <span class="n">MaximumLength</span> <span class="p">=</span> <span class="m">100</span> <span class="p">});</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Field</span><span class="p">(</span><span class="n">c</span> <span class="p">=&gt;</span> <span class="n">c</span><span class="p">.</span><span class="n">LastName</span><span class="p">)</span> <span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">StringType</span><span class="p">&gt;&gt;()</span> <span class="p">.</span><span class="nf">Directive</span><span class="p">(</span><span class="k">new</span> <span class="nf">RequiredDirective</span><span class="p">())</span> <span class="p">.</span><span class="nf">Directive</span><span class="p">(</span><span class="k">new</span> <span class="n">StringLengthDirective</span> <span class="p">{</span> <span class="n">MaximumLength</span> <span class="p">=</span> <span class="m">100</span> <span class="p">});</span> </code></pre></div></div> <p>This gives us the correct schema, but we’ve missed on our goal of only definining our validation rules once.</p> <h3 id="using-modelmetadata">Using ModelMetadata</h3> <p>The next step is using the model metadata provided to us to automatically discover which validation directives to apply to our schema. Here it’s important to understand a bit about how Hot Chocolate creates the schema for out types. First it will call <code class="highlighter-rouge">Configure</code> above and then infer fields based off properties on the type (this is why we didn’t need define <code class="highlighter-rouge">FistName</code> in the first example above). This means we need a hook point after the inference of the fields to then go through all of the fields and add our directives. This is called <a href="https://hotchocolate.io/docs/extending-types">type extension</a> in Hot Chocolate and the hook we’re looking for is <code class="highlighter-rouge">OnBeforeCreate</code>.</p> <p>First we’ll create an extension method onto the type descriptor that makes use of the type extension system.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="n">IInputObjectTypeDescriptor</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">AddValidationDirectives</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">IInputObjectTypeDescriptor</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">descriptor</span><span class="p">,</span> <span class="n">IModelMetadataProvider</span> <span class="n">metadataProvider</span><span class="p">)</span> <span class="p">{</span> <span class="n">descriptor</span> <span class="p">.</span><span class="nf">Extend</span><span class="p">()</span> <span class="p">.</span><span class="nf">OnBeforeCreate</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="nf">AddValidationDirectives</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">metadataProvider</span><span class="p">));</span> <span class="k">return</span> <span class="n">descriptor</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>and then the meat of the whole approach, we use the metadata provider to find all properties that have validators. We then locate the matching field based on name and attach directives based on which validation attributes are provided.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="k">void</span> <span class="nf">AddValidationDirectives</span><span class="p">(</span><span class="n">InputObjectTypeDefinition</span> <span class="n">definition</span><span class="p">,</span> <span class="n">IModelMetadataProvider</span> <span class="n">metadataProvider</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">metadata</span> <span class="p">=</span> <span class="n">metadataProvider</span><span class="p">.</span><span class="nf">GetMetadataForType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">CreateCommunityMemberInput</span><span class="p">));</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">propertyMetadata</span> <span class="k">in</span> <span class="n">metadata</span><span class="p">.</span><span class="n">Properties</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">HasValidators</span> <span class="p">??</span> <span class="k">false</span><span class="p">))</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">field</span> <span class="p">=</span> <span class="n">definition</span><span class="p">.</span><span class="n">Fields</span><span class="p">.</span><span class="nf">SingleOrDefault</span><span class="p">(</span><span class="n">f</span> <span class="p">=&gt;</span> <span class="n">f</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">propertyMetadata</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">));</span> <span class="k">if</span> <span class="p">(</span><span class="n">field</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">validator</span> <span class="k">in</span> <span class="n">propertyMetadata</span><span class="p">.</span><span class="n">ValidatorMetadata</span><span class="p">)</span> <span class="p">{</span> <span class="k">switch</span> <span class="p">(</span><span class="n">validator</span><span class="p">)</span> <span class="p">{</span> <span class="k">case</span> <span class="n">RequiredAttribute</span> <span class="n">required</span><span class="p">:</span> <span class="n">field</span><span class="p">.</span><span class="n">Directives</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">DirectiveDefinition</span><span class="p">(</span><span class="k">new</span> <span class="nf">RequiredDirective</span><span class="p">()));</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="n">StringLengthAttribute</span> <span class="n">stringLength</span><span class="p">:</span> <span class="n">field</span><span class="p">.</span><span class="n">Directives</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">DirectiveDefinition</span><span class="p">(</span><span class="k">new</span> <span class="n">StringLengthDirective</span> <span class="p">{</span> <span class="n">MaximumLength</span> <span class="p">=</span> <span class="n">stringLength</span><span class="p">.</span><span class="n">MaximumLength</span> <span class="p">}));</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>Our schema code then simply becomes</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">CreatePersonInputType</span> <span class="p">:</span> <span class="n">InputObjectType</span><span class="p">&lt;</span><span class="n">CreatePersonInput</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">readonly</span> <span class="n">IModelMetadataProvider</span> <span class="n">_metadataProvider</span><span class="p">;</span> <span class="k">public</span> <span class="nf">CreateCommunityMemberInputType</span><span class="p">(</span><span class="n">IModelMetadataProvider</span> <span class="n">metadataProvider</span><span class="p">)</span> <span class="p">{</span> <span class="n">_metadataProvider</span> <span class="p">=</span> <span class="n">metadataProvider</span><span class="p">;</span> <span class="p">}</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IInputObjectTypeDescriptor</span><span class="p">&lt;</span><span class="n">CreateCommunityMemberInput</span><span class="p">&gt;</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="k">base</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">descriptor</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Field</span><span class="p">(</span><span class="n">c</span> <span class="p">=&gt;</span> <span class="n">c</span><span class="p">.</span><span class="n">LastName</span><span class="p">)</span> <span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">StringType</span><span class="p">&gt;&gt;();</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">AddValidationDirectives</span><span class="p">(</span><span class="n">_metadataProvider</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h3 id="conclusion">Conclusion</h3> <p>We now have in place an extensible approach for defining our validation once per model and then exposing via the GraphQL schema to consuming clients.</p> <p>Next time we’ll look at automatically validating those arguments on the server.</p> Fri, 21 Jun 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/grapql-validation-metadata http://compiledexperience.com/blog/posts/grapql-validation-metadata nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql A better approach to GraphQL renames <p>As it typically happens I write a post on how I do something, it gets some decent traffic and then I find a better way to do it.</p> <p>In this case I’m referring to a post from a few weeks ago about <a href="/blog/posts/stitched-graphql-rename">Handling name collisions in GraphQL schema stitching</a>, in that post I highlighted a way to use <code class="highlighter-rouge">AddMergedDocumentRewriter</code> to rewrite the merged schema document. It turns out there’s a better way…</p> <p><a href="https://hotchocolate.io/">Hot Chocolate</a> supports an <code class="highlighter-rouge">ITypeRewriter</code> interface that when registered will be called for each type in the merged schema. Our <code class="highlighter-rouge">RenameTypeRewriter</code> looks like the following which is a lot cleaner in my opinion.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">RenameTypeRewriter</span> <span class="p">:</span> <span class="n">ITypeRewriter</span> <span class="p">{</span> <span class="k">public</span> <span class="n">ITypeDefinitionNode</span> <span class="nf">Rewrite</span><span class="p">(</span><span class="n">ISchemaInfo</span> <span class="n">schema</span><span class="p">,</span> <span class="n">ITypeDefinitionNode</span> <span class="n">typeDefinition</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">renameDirective</span> <span class="p">=</span> <span class="n">typeDefinition</span><span class="p">.</span><span class="n">Directives</span><span class="p">.</span><span class="nf">SingleOrDefault</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">d</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">Value</span> <span class="p">==</span> <span class="n">RenameDirectiveType</span><span class="p">.</span><span class="n">DirectiveName</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">renameDirective</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">newNameArgumment</span> <span class="p">=</span> <span class="n">renameDirective</span><span class="p">.</span><span class="n">Arguments</span><span class="p">.</span><span class="nf">Single</span><span class="p">(</span><span class="n">a</span> <span class="p">=&gt;</span> <span class="n">a</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">Value</span> <span class="p">==</span> <span class="n">RenameDirectiveType</span><span class="p">.</span><span class="n">ArgumentName</span> <span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">newNameArgumment</span><span class="p">.</span><span class="n">Value</span> <span class="k">is</span> <span class="n">StringValueNode</span> <span class="n">stringValue</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">typeDefinition</span><span class="p">.</span><span class="nf">Rename</span><span class="p">(</span><span class="n">stringValue</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="n">schema</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">return</span> <span class="n">typeDefinition</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>Instead of our call to <code class="highlighter-rouge">AddMergedDocumentRewriter</code> we now have</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">.</span><span class="nf">AddTypeRewriter</span><span class="p">(</span><span class="k">new</span> <span class="nf">RenameTypeRewriter</span><span class="p">())</span> </code></pre></div></div> Tue, 04 Jun 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/better-rename http://compiledexperience.com/blog/posts/better-rename nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql Be careful of lazy dependencies <h2 id="what-are-lazy-dependencies">What are lazy dependencies?</h2> <p>.NET Core has a lot more built in support for dependency injection which is an incredibly useful feature and this post isn’t about not using that, but to think about how and when your depdendencies are created. By dependencies I mean any object being created by your Container which is a pretty broad definition which typically covers controllers, services and more.</p> <p>My definition of a lazy dependency is on that’s created by the container the first time it’s required. I think of it as being orthognal to the lifetime of the dependency as singleton dependecies can be lazy as well as transient ones (the differences is in how often they’re created and not when). For most our services this isn’t an issue as often the creation of our dependency doesn’t execute any significant code, the constructors often look something like the following:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="nf">ProductsController</span><span class="p">(</span><span class="n">IProductRepository</span> <span class="n">repository</span><span class="p">,</span> <span class="n">IEventBus</span> <span class="n">events</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="n">repository</span> <span class="p">=</span> <span class="n">repository</span><span class="p">;</span> <span class="k">this</span><span class="p">.</span><span class="n">events</span> <span class="p">=</span> <span class="n">events</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>This code is unlikely to fail so I don’t have concerns about <code class="highlighter-rouge">ProductsController</code> being lazy. In fact most of our dependencies are lazy (the one’s that aren’t are usually the ones registered as already instantiated objects into the container) and it’s not a problem.</p> <h2 id="which-ones-should-i-be-careful-of">Which ones should I be careful of?</h2> <p>If a majority of our dependencies are lazy what are the ones I should be careful of? In my opinion it’s the ones that have any significant behaviour in their constructors, this could be reading files or opening connections for example. If our <code class="highlighter-rouge">IEventBus</code> implementation establishes a connection to the messaging solution on instantiation then we need to think about what happens if it fails or takes a significant amount of time.</p> <p>This lazy evaluation means the first request to the <code class="highlighter-rouge">ProductsController</code> will be slower due to paying the cost of connecting to the message bus or may fail if that connection fails.</p> <p>A more concrete example comes from our work implementing a GraphQL server using <a href="https://hotchocolate.io/">Hot Chocolate</a>. In GraphQL frameworks you start with the definition of your GraphQL schema, in Hot Chocolate this is represented by the <code class="highlighter-rouge">ISchema</code> interface and configured at start up. However the actual creation of the schema is lazy and doesn’t happy until the first GraphQL request is received which is a little slower but if I’ve misconfigured my schema I don’t see the error till that first request instead of the application startup.</p> <h2 id="why-failing-fast-can-be-good">Why failing fast can be good</h2> <p>Modern deployment strategies (with and without containers) tend to involve standing up the new verison of the application, moving traffic across to the new version and then tearing down the previous version. This enables a seamless deployment experience for the users of the application. However for this to happen the system needs to be able to determine if the system is healthy and the old version can be torn down. If I create a new version where the schema is misconfigured then what want to see happen is the new version is deployed but at start up fails fast, this can then short circuit the deployment system such that previous version keeps serving traffic.</p> <p>Other examples of things we fail fast on are if we detect that there are pending database migrations, this signals that we’re deploying code that is depending on a database migration that hasn’t been deployed to the database. We never want that code to execute so we fail fast and leave the previous version executing.</p> <h2 id="forcing-evaluation">Forcing evaluation</h2> <p>In the examples above we can fail fast by throwing exceptions (this is what we do when there are pending migrations), but for our GraphQL schema example we have a simple extension method.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">/// &lt;summary&gt;</span> <span class="c1">/// Resolves the GraphQL schema forcing validation and ensures any errors before start up failures</span> <span class="c1">/// &lt;/summary&gt;</span> <span class="k">public</span> <span class="k">static</span> <span class="n">IApplicationBuilder</span> <span class="nf">ResolveGraphQLSchema</span><span class="p">(</span><span class="k">this</span> <span class="n">IApplicationBuilder</span> <span class="n">applicationBuilder</span><span class="p">)</span> <span class="p">{</span> <span class="k">try</span> <span class="p">{</span> <span class="n">applicationBuilder</span><span class="p">.</span><span class="n">ApplicationServices</span><span class="p">.</span><span class="n">GetRequiredService</span><span class="p">&lt;</span><span class="n">ISchema</span><span class="p">&gt;();</span> <span class="k">return</span> <span class="n">applicationBuilder</span><span class="p">;</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">StartupFailureException</span><span class="p">(</span><span class="s">"Failed to resolve the sitched GraphQL schema"</span><span class="p">,</span> <span class="n">ex</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>and then called during start up.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">,</span> <span class="n">ILoggerFactory</span> <span class="n">loggerFactory</span><span class="p">,</span> <span class="n">IApplicationLifetime</span> <span class="n">appLifetime</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="n">app</span><span class="p">.</span><span class="nf">ResolveGraphQLSchema</span><span class="p">();</span> <span class="p">...</span> <span class="p">}</span> </code></pre></div></div> <h2 id="summary">Summary</h2> <ul> <li>Most container depdendencies are “lazy”, only instantiated when required.</li> <li>This isn’t a problem when there is no logic in their constructors.</li> <li>When there is we may see errors or slow downs on first requests.</li> <li>Given modern deployment strategies failing fast is a better pattern.</li> <li>We can fore evaluation of these dependencies to move to “fail fast” semantics.</li> </ul> Thu, 23 May 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/lazy-dependencies http://compiledexperience.com/blog/posts/lazy-dependencies nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql Handling name collisions in GraphQL schema stitching <p><strong>GraphQL Schema Stitching</strong> is the mechanism of composing multiple GraphQL schemas together into a single unified schema. This plays strongly into the concept of “back-ends for front-ends” which is building a specialised API designed specifically for the app in question. This “API Gateway” takes the schemas of the micro-services needed for it’s functionality, combines, extends and exposes them to the front end.</p> <p>In the .NET ecosystem the framework <a href="https://hotchocolate.io/">Hot Chocolate</a> has excellent support for stitching together multiple remote schemas as well as customising and extending them. If you’re working with GraphQL in this ecosystem I’d recommend checking it out.</p> <h2 id="name-collisions">Name collisions</h2> <p>GraphQL has no concept of namespacing and enforces unique names on types, so how should we deal with two different schemas exposing types with the same name?</p> <h3 id="pseudo-namespaces">Pseudo-namespaces</h3> <p>Some companies have solved this by introducing a namespace concept by prefixing all types in the schema with the service name. The schema for the Orders service may look like the following. While this works and should guarantee that you have no collisions it cam make for some ugly looking schemas.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>type Orders_LineItem { productId; ID! quantity: Int! } type Orders_Order { id: ID! items: [Orders_LineItem!]! } type Query { orders(customerId: ID!): [Orders_Order!]! } </code></pre></div></div> <h3 id="renaming">Renaming</h3> <p>Another approach is to “rename” the type at the stitched schema if your framework supports it, thankfully <a href="https://hotchocolate.io/">Hot Chocolate</a> does. The <code class="highlighter-rouge">IStitchingBuilder</code> lets us rename types as we build our new schema. The following snippet stitches our Customers and Orders schemas and renames the <code class="highlighter-rouge">Customer</code> type in the Orders schema to <code class="highlighter-rouge">CustomerDetails</code>.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">services</span><span class="p">.</span><span class="nf">AddStitchedSchema</span><span class="p">(</span><span class="n">builder</span> <span class="p">=&gt;</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">AddSchemaFromFile</span><span class="p">(</span><span class="s">"customers"</span><span class="p">,</span> <span class="s">"./schemas/customers.graphql"</span><span class="p">)</span> <span class="p">.</span><span class="nf">AddSchemaFromFile</span><span class="p">(</span><span class="s">"orders"</span><span class="p">,</span> <span class="s">"./schemas/orders.graphql"</span><span class="p">)</span> <span class="p">.</span><span class="nf">RenameType</span><span class="p">(</span><span class="s">"orders"</span><span class="p">,</span> <span class="s">"Customer"</span><span class="p">,</span> <span class="s">"CustomerDetails"</span><span class="p">)</span> </code></pre></div></div> <p>While this works it feels very <em>stringly typed</em> and if you have a number of renames to do would become difficult to maintain. How can we do this better?</p> <p>One extension point provided is <code class="highlighter-rouge">AddMergedDocumentRewriter</code>, this takes a <code class="highlighter-rouge">Func&lt;DocumentNode, DocumentNode&gt;</code> and lets you make any customisations and additions to the schema programmatically. So let’s see if we can build a way to specify the renames in the schema files rather than in code.</p> <p>The question of “Why we’re using <code class="highlighter-rouge">AddSchemaFromFile</code> instead of <code class="highlighter-rouge">AddSchemaFromHttp</code> is a blog post for another day, but it certainlu helps us here.</p> <p>Our end goal will be to remove the <code class="highlighter-rouge">RenameType</code> call and instead inside the <code class="highlighter-rouge">orders.graphql</code> have something like</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>type Customer @rename(name: "CustomerDetails") { id: ID! firstName: String! ... } </code></pre></div></div> <h2 id="rewriting-the-stitched-schema">Rewriting the stitched schema</h2> <p>First we should define our <code class="highlighter-rouge">rename</code> directive, Directives are the mechanism to add metadata to GraphQL schemas much like C# attributes.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">RenameDirectiveType</span> <span class="p">:</span> <span class="n">DirectiveType</span> <span class="p">{</span> <span class="k">public</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">DirectiveName</span> <span class="p">=</span> <span class="s">"rename"</span><span class="p">;</span> <span class="k">public</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">ArgumentName</span> <span class="p">=</span> <span class="s">"name"</span><span class="p">;</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IDirectiveTypeDescriptor</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="n">DirectiveName</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Location</span><span class="p">(</span><span class="n">DirectiveLocation</span><span class="p">.</span><span class="n">Object</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Argument</span><span class="p">(</span><span class="n">ArgumentName</span><span class="p">)</span> <span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">NameType</span><span class="p">&gt;&gt;();</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>We can now build our document rewriter to use this directive</p> <blockquote> <p><strong>Update</strong> I’ve found a better way to do the following, documented at <a href="/blog/posts/better-rename"> A better approach to GraphQL renames</a>.</p> </blockquote> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Rewriters</span> <span class="p">{</span> <span class="k">public</span> <span class="k">static</span> <span class="n">DocumentNode</span> <span class="nf">RenameTypes</span><span class="p">(</span><span class="n">DocumentNode</span> <span class="n">document</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">definitions</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IDefinitionNode</span><span class="p">&gt;();</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">definition</span> <span class="k">in</span> <span class="n">document</span><span class="p">.</span><span class="n">Definitions</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">definition</span> <span class="k">is</span> <span class="n">ObjectTypeDefinitionNode</span> <span class="n">typeDefinition</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">renameDirective</span> <span class="p">=</span> <span class="n">typeDefinition</span><span class="p">.</span><span class="n">Directives</span><span class="p">.</span><span class="nf">SingleOrDefault</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">d</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">Value</span> <span class="p">==</span> <span class="n">RenameDirectiveType</span><span class="p">.</span><span class="n">DirectiveName</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">renameDirective</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">newNameArgumment</span> <span class="p">=</span> <span class="n">renameDirective</span><span class="p">.</span><span class="n">Arguments</span><span class="p">.</span><span class="nf">Single</span><span class="p">(</span><span class="n">a</span> <span class="p">=&gt;</span> <span class="n">a</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">Value</span> <span class="p">==</span> <span class="n">RenameDirectiveType</span><span class="p">.</span><span class="n">ArgumentName</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">newNameArgumment</span><span class="p">.</span><span class="n">Value</span> <span class="k">is</span> <span class="n">StringValueNode</span> <span class="n">stringValue</span><span class="p">)</span> <span class="p">{</span> <span class="n">definitions</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">typeDefinition</span><span class="p">.</span><span class="nf">WithName</span><span class="p">(</span><span class="k">new</span> <span class="nf">NameNode</span><span class="p">(</span><span class="n">stringValue</span><span class="p">.</span><span class="n">Value</span><span class="p">)));</span> <span class="k">continue</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="n">definitions</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">definition</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="n">document</span><span class="p">.</span><span class="nf">WithDefinitions</span><span class="p">(</span><span class="n">definitions</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>This looks pretty complex but isn’t too bad. It’s important to note that <code class="highlighter-rouge">DocumentNode</code> is immutable, so we build a new one with the renamed types, the <code class="highlighter-rouge">WithDefinitions</code> helper does this, essentially returning a new <code class="highlighter-rouge">DocumentNode</code> which is the same as the old but with different type definitions.</p> <p>The rest of the code simply loops over all the type definitions in the document and examines the object type ones closer (if you wanted to support renaming fields this becomes a little more complex), if this object type definition has the rename directive then get the argument value and add the renamed definition to the list.</p> <p>We can now use our rewriter as follows</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">services</span><span class="p">.</span><span class="nf">AddStitchedSchema</span><span class="p">(</span><span class="n">builder</span> <span class="p">=&gt;</span> <span class="n">builder</span> <span class="p">.</span><span class="nf">AddSchemaFromFile</span><span class="p">(</span><span class="s">"customers"</span><span class="p">,</span> <span class="s">"./schemas/customers.graphql"</span><span class="p">)</span> <span class="p">.</span><span class="nf">AddSchemaFromFile</span><span class="p">(</span><span class="s">"orders"</span><span class="p">,</span> <span class="s">"./schemas/orders.graphql"</span><span class="p">)</span> <span class="p">.</span><span class="nf">AddMergedDocumentRewriter</span><span class="p">(</span><span class="n">Rewriters</span><span class="p">.</span><span class="n">RenameTypes</span><span class="p">)</span> </code></pre></div></div> <p>We can now handle all our renames in the schema files rather than using magic strings in code.</p> <h2 id="summary">Summary</h2> <ul> <li>GraphQL schema stiching combines multiple schemas in single exposed schema.</li> <li>Given the lack of namespaces in the specification we need to handle type name collisions between the schema.</li> <li>While Hot Chocolate supports renaming types the mechanism leads to a lot of hard to maintain code.</li> <li>Building our own document rewriter lets us do directive based renames.</li> </ul> <p>Hope this helps someone.</p> Wed, 08 May 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/stitched-graphql-rename http://compiledexperience.com/blog/posts/stitched-graphql-rename nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql My git aliases <p>I’ve seen a few posts around lately with people discussing how they work with git during day to day development and I thought I’d share mine.</p> <p>I use a combination of <a href="https://desktop.github.com/">GitHub Desktop</a> and the command line. I prefer a UI for crafting my commits, being able to select which files and / or lines I’d like to include is incredibly easy in the UI.</p> <p>For everything else such as rebasing, pulling etc I use the command line, usually Powershell inside <a href="https://cmder.net/">Cmder</a> and using <a href="https://github.com/dahlbyk/posh-git">posh-git</a>.</p> <p>Below are the aliases I use reasonably consistently, one theme through these is that I’m not optimising for keystrokes, but “brain space”.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>graph = log --oneline --graph --decorate --all branches = branch -a tags = tag stashes = stash list unstage = reset -q HEAD -- discard = checkout -- uncommit = reset --mixed HEAD~ amend = commit --amend --no-edit nevermind = !git reset --hard HEAD &amp;&amp; git clean -xdf remotes = remote -v fixup = commit --fixup overwrite = push --force-with-lease rewrite="!f() { \ COMMIT_COUNT=$(git rev-list --count HEAD ^master); \ git rebase -i --autosquash HEAD~$COMMIT_COUNT; \ };f" publish="!f() { \ BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD); \ git push -u origin $BRANCH_NAME; \ };f" browse = "!f() { \ REPO_URL=$(git config remote.origin.url); \ start ${REPO_URL%%.git}; \ };f" pr = "!f() { \ REPO_URL=$(git config remote.origin.url); \ BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD); \ start \"${REPO_URL%%.git}/compare/${BRANCH_NAME}?expand=1\"; \ };f" jira = "!f() { \ BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD); \ start \"https://pushpay.atlassian.net/browse/${BRANCH_NAME}\"; \ };f" </code></pre></div></div> <p>Hope others find these useful.</p> Fri, 05 Apr 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/git-alias-2019 http://compiledexperience.com/blog/posts/git-alias-2019 nigel.sampson@compiledexperience.com (Nigel Sampson) git Guarding against N+1 issues in GraphQL <p>The <strong>N+1 query problem</strong> is a common one to encounter during software development, particularly with ORMs (Object Relational Mappers) and their capabilities around lazy loading. A quick example looks like</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">orders</span> <span class="p">=</span> <span class="nf">GetOrders</span><span class="p">();</span> <span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">order</span> <span class="k">in</span> <span class="n">orders</span><span class="p">)</span> <span class="p">{</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"</span><span class="p">{</span><span class="n">order</span><span class="p">.</span><span class="n">Customer</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> made an order on </span><span class="p">{</span><span class="n">order</span><span class="p">.</span><span class="n">CreatedOn</span><span class="p">}</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span> </code></pre></div></div> <p>Unless you’re careful, the lazy loading of the <code class="highlighter-rouge">Customer</code> of the <code class="highlighter-rouge">Order</code> results in a database query, for 100 orders this would result in 101 database calls, one per <code class="highlighter-rouge">Customer</code> and one extra for the orders (hence the name N+1).</p> <p>I won’t go into the ways we can solve this in ORMs as this is a well documented problem with a myriad of approaches to avoid it.</p> <h2 id="graphql-and-n1">GraphQL and N+1</h2> <p>When we look at a typical GraphQL query we can see the makings of the same problem.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>query { orders { createdOn customer { name } } } </code></pre></div></div> <p>Whether the above query results in N+1 database queries is completely up to the the implementation of the resolvers. Most GraphQL server frameworks support the idea of a <code class="highlighter-rouge">DataLoader</code>. A Dataloader allows you to batch the <code class="highlighter-rouge">Customer</code> requests into a single query and put the correct <code class="highlighter-rouge">Customer</code> into the correct location of the results. For better examples you can view the documentation for <a href="https://hotchocolate.io/docs/dataloaders">Hot Chocolate</a>, a popular .NET GraphQL server framework. This only works when the underlying data source supports a performant batch operation (in these case getting a list of customers based on a list of ids).</p> <h2 id="when-dataloader-wont-work">When DataLoader won’t work</h2> <p>Sometimes however this batch operation isn’t supported and we’re left with our N+1 performance problem, what can we do?</p> <p>Let’s assume our Orders and Customers data live in different microservices and that Customers microservice doesn’t support a batch operation for requesting a list of Customers.</p> <p>In that case a query like the above one wouldn’t be performant, resulting in N requests to the underlying Customer microservice, however a query like the following would only result in a single call.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>query { order("b3JkZXI6NDI=") { createdOn customer { name } } } </code></pre></div></div> <p>So how do we ensure one is valid, but one is invalid? The easiest way would be to define different <code class="highlighter-rouge">Order</code> types in our schema, one that has <code class="highlighter-rouge">customer</code> field and one doesn’t and never expose the former in a list field. While it works it would cause a long term maintenance problem as we struggle to keep these types in sync and doesn’t create a particularly nice graph.</p> <p>Instead we’re going to play with the <a href="https://hotchocolate.io/docs/validation-rule">validation rules</a> feature of Hot Chocolate. We’ll create a rule that the <code class="highlighter-rouge">customer</code> field can only be included in a query where none of its parent fields are a list. This would ensure the latter query is valid while the former is invalid.</p> <p>One really nice feature about validation rules are that they’re done during the parsing of the query document. This means the validation result can be cached along with the parsing result. This way if you’re sending constant queries (where only the variables are different) then the validation rule won’t be executed that often.</p> <h2 id="creating-the-directive">Creating the Directive</h2> <p>First we need to create a directive, these function in much the same way as C# attributes, a way to attach metadata to our GraphQL schema that other code can introspect and make use of. In this case we’ll define an <code class="highlighter-rouge">includeOnce</code>.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceDirectiveType</span> <span class="p">:</span> <span class="n">DirectiveType</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IDirectiveTypeDescriptor</span> <span class="n">descriptor</span><span class="p">)</span> <span class="p">{</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Name</span><span class="p">(</span><span class="s">"includeOnce"</span><span class="p">);</span> <span class="n">descriptor</span><span class="p">.</span><span class="nf">Location</span><span class="p">(</span><span class="n">DirectiveLocation</span><span class="p">.</span><span class="n">FieldDefinition</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>This directive doesn’t have any behavior and simply functions as a “marker” for our validation rule. If we’re doing schema first development we register the directive in the schema.</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>type Order { ... customer: Customer @includeOnce } </code></pre></div></div> <p>While in code first it would be in the field definition</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">descriptor</span><span class="p">.</span><span class="nf">Field</span><span class="p">(</span><span class="s">"customer"</span><span class="p">)</span> <span class="p">.</span><span class="n">Directive</span><span class="p">&lt;</span><span class="n">IncludeOnceDirectiveType</span><span class="p">&gt;()</span> <span class="p">.</span><span class="n">Type</span><span class="p">&lt;</span><span class="n">NonNullType</span><span class="p">&lt;</span><span class="n">CustomerType</span><span class="p">&gt;&gt;()</span> <span class="p">...</span> </code></pre></div></div> <p>The directive also needs to be registered with the schema itself.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">c</span><span class="p">.</span><span class="n">RegisterDirective</span><span class="p">&lt;</span><span class="n">IncludeOnceDirectiveType</span><span class="p">&gt;();</span> </code></pre></div></div> <h2 id="creating-the-validation-rule">Creating the validation rule</h2> <p>The implementation of the validation rule can be quite complex, the code below illustrates the concept but doesn’t cover some of the more complex cases (such as mutations). For a more fully featured example I suggest the <a href="https://github.com/ChilliCream/hotchocolate/blob/master/src/Core/Core/Validation/MaxComplexityRule.cs"><code class="highlighter-rouge">MaxComplexityRule</code></a> and <a href="https://github.com/ChilliCream/hotchocolate/blob/master/src/Core/Core/Validation/MaxComplexityVisitor.cs"><code class="highlighter-rouge">MaxComplexityVisitor</code></a> from the core repository.</p> <p>What we need to do is create a <code class="highlighter-rouge">QuerySyntaxWalker</code> that supports the traversal of the AST (abstract syntax tree), if you’ve done anything with Roslyn some of this will look familiar.</p> <p>It can look complicated, but we’re visiting each field within the query and maintaining some context from the parent fields we’ve visited. If we find a field whose definition has the <code class="highlighter-rouge">includeOnce</code> directive then we examine the list of parent fields, if any are a list type then we report an error.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceVisitor</span> <span class="p">:</span> <span class="n">QuerySyntaxWalker</span><span class="p">&lt;</span><span class="n">IncludeOnceContext</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">protected</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">VisitFragmentDefinitions</span> <span class="p">=&gt;</span> <span class="k">false</span><span class="p">;</span> <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">VisitField</span><span class="p">(</span><span class="n">FieldNode</span> <span class="n">node</span><span class="p">,</span> <span class="n">IncludeOnceContext</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">newContext</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">TypeContext</span> <span class="k">is</span> <span class="n">IComplexOutputType</span> <span class="n">type</span> <span class="p">&amp;&amp;</span> <span class="n">type</span><span class="p">.</span><span class="n">Fields</span><span class="p">.</span><span class="nf">TryGetField</span><span class="p">(</span><span class="n">node</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="k">out</span> <span class="n">IOutputField</span> <span class="n">fieldDefinition</span><span class="p">))</span> <span class="p">{</span> <span class="n">newContext</span> <span class="p">=</span> <span class="n">newContext</span><span class="p">.</span><span class="nf">WithField</span><span class="p">(</span><span class="n">fieldDefinition</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">fieldDefinition</span><span class="p">.</span><span class="n">Type</span><span class="p">.</span><span class="nf">NamedType</span><span class="p">()</span> <span class="k">is</span> <span class="n">IComplexOutputType</span> <span class="n">ct</span><span class="p">)</span> <span class="p">{</span> <span class="n">newContext</span> <span class="p">=</span> <span class="n">newContext</span><span class="p">.</span><span class="nf">SetTypeContext</span><span class="p">(</span><span class="n">ct</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">fieldDefinition</span><span class="p">.</span><span class="n">Directives</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"includeOnce"</span><span class="p">))</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">includedMoreThanOnce</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">FieldPath</span><span class="p">.</span><span class="nf">Any</span><span class="p">(</span><span class="n">f</span> <span class="p">=&gt;</span> <span class="n">f</span><span class="p">.</span><span class="n">Type</span><span class="p">.</span><span class="nf">IsListType</span><span class="p">());</span> <span class="k">if</span> <span class="p">(</span><span class="n">includedMoreThanOnce</span><span class="p">)</span> <span class="p">{</span> <span class="n">newContext</span><span class="p">.</span><span class="nf">ReportError</span><span class="p">(</span><span class="k">new</span> <span class="nf">ValidationError</span><span class="p">(</span><span class="s">$"The field </span><span class="p">{</span><span class="n">node</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s"> can only be includes once in a query"</span><span class="p">,</span> <span class="n">node</span><span class="p">));</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">base</span><span class="p">.</span><span class="nf">VisitField</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">newContext</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceContext</span> <span class="p">{</span> <span class="k">public</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">ISchema</span> <span class="n">schema</span><span class="p">,</span> <span class="n">Action</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;</span> <span class="n">reportError</span><span class="p">)</span> <span class="p">{</span> <span class="n">Schema</span> <span class="p">=</span> <span class="n">schema</span><span class="p">;</span> <span class="n">FieldPath</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IOutputField</span><span class="p">&gt;();</span> <span class="n">ReportError</span> <span class="p">=</span> <span class="n">reportError</span><span class="p">;</span> <span class="p">}</span> <span class="k">protected</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">ISchema</span> <span class="n">schema</span><span class="p">,</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IOutputField</span><span class="p">&gt;</span> <span class="n">fieldPath</span><span class="p">,</span> <span class="n">Action</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;</span> <span class="n">reportError</span><span class="p">)</span> <span class="p">{</span> <span class="n">Schema</span> <span class="p">=</span> <span class="n">schema</span><span class="p">;</span> <span class="n">FieldPath</span> <span class="p">=</span> <span class="n">fieldPath</span><span class="p">.</span><span class="nf">ToList</span><span class="p">();</span> <span class="n">ReportError</span> <span class="p">=</span> <span class="n">reportError</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">Action</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;</span> <span class="n">ReportError</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">IList</span><span class="p">&lt;</span><span class="n">IOutputField</span><span class="p">&gt;</span> <span class="n">FieldPath</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">ISchema</span> <span class="n">Schema</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">INamedOutputType</span> <span class="n">TypeContext</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">protected</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="n">IncludeOnceContext</span> <span class="nf">WithField</span><span class="p">(</span><span class="n">IOutputField</span> <span class="n">field</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">Schema</span><span class="p">,</span> <span class="n">FieldPath</span><span class="p">.</span><span class="nf">Concat</span><span class="p">(</span><span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="n">field</span> <span class="p">}),</span> <span class="n">ReportError</span><span class="p">);</span> <span class="p">}</span> <span class="k">public</span> <span class="n">IncludeOnceContext</span> <span class="nf">SetTypeContext</span><span class="p">(</span><span class="n">INamedOutputType</span> <span class="n">typeContext</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">Schema</span><span class="p">,</span> <span class="n">FieldPath</span><span class="p">,</span> <span class="n">ReportError</span><span class="p">)</span> <span class="p">{</span> <span class="n">TypeContext</span> <span class="p">=</span> <span class="n">typeContext</span> <span class="p">};</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>After all this, the validation rule itself is pretty straightforward. Create a visitor, explore the document, then report if there are any errors.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">IncludeOnceValidationRule</span> <span class="p">:</span> <span class="n">IQueryValidationRule</span> <span class="p">{</span> <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">IncludeOnceVisitor</span> <span class="n">includeOnceVisitor</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">IncludeOnceVisitor</span><span class="p">();</span> <span class="k">public</span> <span class="n">QueryValidationResult</span> <span class="nf">Validate</span><span class="p">(</span><span class="n">ISchema</span> <span class="n">schema</span><span class="p">,</span> <span class="n">DocumentNode</span> <span class="n">queryDocument</span><span class="p">)</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">errors</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IError</span><span class="p">&gt;();</span> <span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">IncludeOnceContext</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="n">errors</span><span class="p">.</span><span class="n">Add</span><span class="p">).</span><span class="nf">SetTypeContext</span><span class="p">(</span><span class="n">schema</span><span class="p">.</span><span class="n">QueryType</span><span class="p">);</span> <span class="n">includeOnceVisitor</span><span class="p">.</span><span class="nf">Visit</span><span class="p">(</span><span class="n">queryDocument</span><span class="p">,</span> <span class="n">context</span><span class="p">);</span> <span class="k">return</span> <span class="n">errors</span><span class="p">.</span><span class="nf">Any</span><span class="p">()</span> <span class="p">?</span> <span class="k">new</span> <span class="nf">QueryValidationResult</span><span class="p">(</span><span class="n">errors</span><span class="p">)</span> <span class="p">:</span> <span class="n">QueryValidationResult</span><span class="p">.</span><span class="n">OK</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>The one final step is register our new validation rule with the schema</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">.</span><span class="nf">AddExecutionConfiguration</span><span class="p">(</span><span class="n">execution</span> <span class="p">=&gt;</span> <span class="n">execution</span> <span class="p">.</span><span class="n">AddValidationRule</span><span class="p">&lt;</span><span class="n">IncludeOnceValidationRule</span><span class="p">&gt;()</span> <span class="p">)</span> </code></pre></div></div> <p>We can now validate that our poorly performing field is only included in queries that will not exacerbate the issue. Hope this helps.</p> Wed, 13 Mar 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/graphql-n+1 http://compiledexperience.com/blog/posts/graphql-n+1 nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql Exporting a GraphQL Schema <p>I’ve been playing around with <a href="https://graphql.org/">GraphQL</a> at work quite a bit lately and starting to put together some thoughts on how it can fit into your application (and more importantly where it doesn’t).</p> <p>One of the things we found we needed everyonce in a while was an export of the schema in the <code class="highlighter-rouge">.graphql</code> format. Most of the time we were definining our schema in a “code first* way using <a href="https://graphql-dotnet.github.io/">GraphQL.NET</a>, so we typically didn’t have this file to work from.</p> <p>However a number of tools / frameworks work well if they can import one of these schemas, a good example is schema stiching using <a href="https://hotchocolate.io/">Hot Chocolate</a>.</p> <p>So how do we export a schema from an already existing <a href="https://graphql-dotnet.github.io/">GraphQL.NET</a> service?</p> <p>Thankfully support comes in terms of the <code class="highlighter-rouge">SchemaPrinter</code> class. This takes an instance of your <code class="highlighter-rouge">Schema</code> that you’ve created by any of the mechanisms the framework supports.</p> <p>Usage looks something like</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">printer</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SchemaPrinter</span><span class="p">(</span><span class="n">_schema</span><span class="p">,</span> <span class="k">new</span> <span class="n">SchemaPrinterOptions</span> <span class="p">{</span> <span class="n">IncludeDeprecationReasons</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span> <span class="n">IncludeDescriptions</span> <span class="p">=</span> <span class="k">true</span> <span class="p">}))</span> <span class="p">{</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">ContentType</span> <span class="p">=</span> <span class="s">"application/text"</span><span class="p">;</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">OK</span><span class="p">;</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="n">printer</span><span class="p">.</span><span class="nf">Print</span><span class="p">());</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>I’m using the code in my GraphQL middleware where if no query was posted then we return the schema.</p> <p>Hope this helps someone.</p> Tue, 26 Feb 2019 00:00:00 +0000 http://compiledexperience.com/blog/posts/exporting-graphql-schema http://compiledexperience.com/blog/posts/exporting-graphql-schema nigel.sampson@compiledexperience.com (Nigel Sampson) csharp graphql