<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Matt Nield</title>
    <description>The latest articles on Forem by Matt Nield (@mattnield).</description>
    <link>https://forem.com/mattnield</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F23220%2Fa5b308f2-c767-4bbb-accf-1d227f70a591.jpg</url>
      <title>Forem: Matt Nield</title>
      <link>https://forem.com/mattnield</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mattnield"/>
    <language>en</language>
    <item>
      <title>Getting the latest content from Kontent.ai</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Wed, 02 Nov 2022 10:04:20 +0000</pubDate>
      <link>https://forem.com/mattnield/getting-the-latest-content-from-kontentai-dha</link>
      <guid>https://forem.com/mattnield/getting-the-latest-content-from-kontentai-dha</guid>
      <description>&lt;p&gt;The &lt;a href="https://kontent.ai"&gt;Kontent.ai&lt;/a&gt; delivery API enables us to retrieve content from the CMS easily. For content that updates regularly, via the management API or frequent content updates it also provides a way to ensure that the content being retrieved is not stale. It's an easy feature to use so long as you know how and when to use it.&lt;/p&gt;

&lt;p&gt;Keeping content up to date is important in any channel. If content updates regularly either via integrations with the CMS or a busy editorial team, we want to make sure that the latest updates are available to our users.&lt;/p&gt;

&lt;p&gt;When we're querying Kontent.ai using the Delivery REST API, there is an &lt;a href="https://kontent.ai/learn/tutorials/develop-apps/integrate/webhooks/#a-get-the-latest-content"&gt;HTTP header we can use that instructs the API to only return fresh data&lt;/a&gt;.  It's named X-KC-Wait-For-Loading-New-Content. &lt;/p&gt;

&lt;p&gt;When this header is set, the API will wait for new content to be processed before data is returned from the API, ignoring any previously cached data for the same request. If we don't set it, then the delivery API will return a cached response to our query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the &lt;code&gt;X-KC-Wait-For-Loading-New-Content&lt;/code&gt; Header
&lt;/h2&gt;

&lt;p&gt;Depending on which stack we're using, how we add the header can look a little different. &lt;/p&gt;

&lt;p&gt;In JavaScript, you can see that the query configuration can be passed in per request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Set wait header in JavaScript&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;KontentDelivery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createDeliveryClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;PROJECT_ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my_post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;waitForLoadingNewContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas the following example in .NET sets up the client as always waiting for fresh content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Set wait header in dotnet&lt;/span&gt;
&lt;span class="n"&gt;IDeliveryClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DeliveryClientBuilder&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithProjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;PROJECT_ID&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseProductionApi&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitForLoadingNewContent&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;IDeliveryItemResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetItemAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"my_post"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Overall, I prefer the JavaScript approach here, as it allows developers to be explicit about when the fresh content is important to our application. With the .NET approach, it feels a little like a sledgehammer and might cause us to think about registering multiple clients to get the best performance for our application. &lt;/p&gt;

&lt;h2&gt;
  
  
  What are we waiting for?
&lt;/h2&gt;

&lt;p&gt;A key thing to note is that, when the header is set, only the root items of the query are checked for freshness. Any linked items/modular content will not wait for stale content to be flushed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xPrf9pR_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnixfsuiwm80p3ccicpk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xPrf9pR_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnixfsuiwm80p3ccicpk.png" alt="Diagram of content item with linked items" width="481" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above diagram, the root item in the query itself has not changed but the linked items have. When we request the root item and include the linked items, the delivery API will return a cached query response.&lt;/p&gt;

&lt;p&gt;In my example, I have a &lt;strong&gt;Courses&lt;/strong&gt; type that has &lt;strong&gt;Availability Slots&lt;/strong&gt; as linked items. A scheduled job keeps my availability slots synchronised with an external service. When these slots are updated, I then create a denormalised view of my data in an Azure Cognitive Search index to allow users to search for courses. But, If I process my data too quickly relying on getting the course and its availability slots in a single query, then I run into problems.   &lt;/p&gt;

&lt;p&gt;To make sure I get the latest versions of the linked items, I request them at the root level of a query as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in order to get the latest availability data, we need to request the slots directly&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;availabilitySlots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;waitForLoadingNewContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system.id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;availability&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This promotes the course availability slots to the root of the query and waits for the updates to finish processing to make sure that the fresh data is returned.&lt;/p&gt;

</description>
      <category>kontent</category>
      <category>webdev</category>
      <category>cms</category>
    </item>
    <item>
      <title>Bulk Update Content Types in Kontent by Kentico</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Fri, 17 Jun 2022 11:04:58 +0000</pubDate>
      <link>https://forem.com/mattnield/bulk-update-content-types-in-kontent-by-kentico-152c</link>
      <guid>https://forem.com/mattnield/bulk-update-content-types-in-kontent-by-kentico-152c</guid>
      <description>&lt;p&gt;Mature projects in any CMS will have a large number of content types. Maintaining those with scripts makes changes to that model more repeatable, but it can be overwhelming if you need to update a lot of types. You can leverage the management API in Kontent by Kentico to update multiple content types in a single script to lessen your workload.&lt;/p&gt;

&lt;p&gt;In a recent project, I've used Cloudinary for all media assets and the &lt;a href="https://github.com/Kentico/kontent-custom-element-cloudinary"&gt;Cloudinary custom element&lt;/a&gt; from the &lt;a href="https://kentico.github.io/kontent-custom-element-samples/gallery/"&gt;custom element gallery&lt;/a&gt;. This has been working for me just fine, but at one point I needed to change the settings for the custom element across the whole project. In this project, we'd added the settings for custom elements each time they were created, so updating my content model with 70 content types was going to take some effort to update.&lt;/p&gt;

&lt;p&gt;As we'd been using the &lt;a href="https://github.com/Kentico/kontent-cli#kentico-kontent-cli"&gt;Kontent CLI&lt;/a&gt; to manage content model changes, each change to the content model results in a new script getting created. When faced with a large update like this, we didn't want to manually script each content type change, so we wrote a script using the Kontent Management API to automate the task.&lt;/p&gt;

&lt;p&gt;To script this, we needed to do three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify the content types and elements that need to be changed&lt;/li&gt;
&lt;li&gt;Prepare the change that we want to be applied&lt;/li&gt;
&lt;li&gt;Loop through the content type list, updating as we go &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our project, the change in question affected sixteen content types. Our method of documenting the content model using &lt;a href="https://miro.com/mind-map/"&gt;Mind Map diagrams in Miro&lt;/a&gt; meant that we could easily identify the types in question and their elements and codenames. So all we needed was a simple array of content type codenames. &lt;/p&gt;

&lt;p&gt;We captured this data in a simple array with the codenames of the content type and elements respectively as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comp_homepage_hero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comp_hero_quote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;menu_item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tile_image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comp_image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comp_hero_slim&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;location_facility&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;icon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comp_hero_tile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;restaurant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tile_image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could have written an additional script to identify the content types that need changing if needed which would mean that the script could be re-run as the content model grows. &lt;/p&gt;

&lt;p&gt;For our update, we were changing the details for our Cloudinary connection. This means that for each content type, we need the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;codename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;replace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/elements/codename:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;codename&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/json_parameters`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;cloudName&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;NEW_CLOUD_NAME&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;apiKey&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;123451234512345&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;${codename}&lt;/code&gt; will be a parameter that we can pass in to determine the name of the element to update.&lt;/p&gt;

&lt;p&gt;Then, we just need to bring it all together by looping through the &lt;code&gt;contentTypes&lt;/code&gt; array as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contentTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modifyContentType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;byTypeCodename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])).&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first time we had this, we did not use &lt;code&gt;await Promise.all(...)&lt;/code&gt;, which confused me for a while. This is important to ensure that all changes are applied before the script ends. &lt;/p&gt;

&lt;p&gt;Once run, this takes all of the content types in our codename array and modifies them. The basic idea of looping here is simple but often overlooked. To make this more reusable, we added this to a utility file in our project so that we could easily re-run it with other changes, such as adding new content types to the allowed list in linked items.&lt;/p&gt;

</description>
      <category>kontent</category>
      <category>contentmodelling</category>
      <category>headlesscms</category>
      <category>tips</category>
    </item>
    <item>
      <title>How to use next/image with cloud providers</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Fri, 20 May 2022 13:11:46 +0000</pubDate>
      <link>https://forem.com/mattnield/how-to-use-nextimage-with-cloud-providers-356o</link>
      <guid>https://forem.com/mattnield/how-to-use-nextimage-with-cloud-providers-356o</guid>
      <description>&lt;p&gt;Using the next/image component in your site is a quick and easy way to add responsive images. If you’re using a cloud-based asset management platform, you need to make sure that you configure it properly in order to get the best performance and benefit from the features that maybe be provided.&lt;/p&gt;

&lt;p&gt;On a previous project, the responsive image implementation didn’t work as I would’ve expected, so I decided to dig further into how it should work. If you’re able to watch it, I created a video that walks through adding the &lt;code&gt;Image&lt;/code&gt; component to a next.js application, configuring it to look at an asset management provider, and adding a custom loader to take advantage of the image capabilities provided rather than having the webserver do all of the work.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gaAut1ETkrU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you’re more inclined to read about it, these are the steps I took.&lt;/p&gt;

&lt;p&gt;First, in Visual Studio Code’s terminal, we can use yarn create next-app and accept the defaults. This created a new folder called my-app that contains our application. We can then run &lt;code&gt;cd my-app&lt;/code&gt; and then &lt;code&gt;code .&lt;/code&gt; (or &lt;code&gt;code . -r&lt;/code&gt; for the current window).&lt;/p&gt;

&lt;p&gt;We then change index.js to remove most of the content and add in a simple image, leaving the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;main className={styles.main}&amp;gt;
  &amp;lt;div className={styles.hero}&amp;gt; &amp;lt;img alt="Styled photo of a retro microphone" className={styles.heroImage} src="/retro-mic.jpg" /&amp;gt;
    &amp;lt;h1 className={styles.title}&amp;gt; Welcome to &amp;lt;a href="https://nextjs.org"&amp;gt;Next.js!&amp;lt;/a&amp;gt; &amp;lt;/h1&amp;gt;
    &amp;lt;p className={styles.description}&amp;gt; Get started by editing &amp;lt;code className={styles.code}&amp;gt;pages/index.js&amp;lt;/code&amp;gt; &amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well also add to the CSS to style things up a little:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* modified to add a position and z-index */ 
.title, .description { 
  position: relative; 
  text-align: center; 
  z-index: 0; } 

/* these two are new to make something look acceptable */ .hero { 
  margin: 1rem; 
  padding: 1.5rem; 
  text-align: left; 
  color: inherit; 
  text-decoration: none; 
  border: 1px solid #eaeaea; 
  border-radius: 10px; 
  transition: color 0.15s ease, border-color 0.15s ease; 
  position: relative; 
  display: flex; 
  align-items: center; 
  justify-content: center; 
  flex-wrap: wrap; 
  max-width: 800px; 
  overflow: hidden; } 

.heroImage { 
  position: absolute; 
  top: 0; 
  left: 0; 
  min-height:100%; 
  width: 100%; 
  height:auto; 
  object-fit: cover; 
  mix-blend-mode:color-burn; 
  z-index: -1; 
  opacity: 0.25; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This just gives us something to look at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TrFUKHvU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/enwzi6pqs5iozh2e1uyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TrFUKHvU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/enwzi6pqs5iozh2e1uyc.png" alt="Our simple page for this example" width="880" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our simple page for this example&lt;br&gt;
If we look in the dev tools when the page load, we see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h7rUNa7p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwmwwcs8ugmm34mefwbq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h7rUNa7p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwmwwcs8ugmm34mefwbq.png" alt="Network traffic for our image in Chrome developer tools" width="880" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Network traffic for our image in Chrome developer tools&lt;br&gt;
Nice, but even when we go down to mobile, we get the same image at the same size and a little over 300kB :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X7K_Tera--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvkbz59wq5mi5b4wd1a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X7K_Tera--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvkbz59wq5mi5b4wd1a6.png" alt="Image size for mobile in Chrome developer tools&amp;lt;br&amp;gt;
" width="720" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image size for mobile in Chrome developer tools&lt;br&gt;
Let’s add some basic formatting and the Image component from next/image tag gives us something a bit nicer.&lt;/p&gt;

&lt;p&gt;When we’ve done that in &lt;code&gt;index.js&lt;/code&gt;, the hero looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className={styles.hero}&amp;gt;
  &amp;lt;Image layout="fill" alt="Styled photo of a retro microphone" className={styles.heroImage} src="/retro-mic.jpg" /&amp;gt;
  &amp;lt;h1 className={styles.title}&amp;gt; Welcome to &amp;lt;a href="https://nextjs.org"&amp;gt;Next.js!&amp;lt;/a&amp;gt; &amp;lt;/h1&amp;gt;
  &amp;lt;p className={styles.description}&amp;gt; Get started by editing &amp;lt;code className={styles.code}&amp;gt;pages/index.js&amp;lt;/code&amp;gt; &amp;lt;/p&amp;gt; &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in next.config.js we add the images element in order to add our default configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const nextConfig = { 
  reactStrictMode: true, 
  images: { 
    loader: 'default', 
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], 
    formats: ['image/webp'], 
  }, 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we restart the app, we can see now, as we resize, new images are created and they’re &lt;code&gt;webp&lt;/code&gt; format:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M1K_2AW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q298blm2ds9bkeafz7yp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M1K_2AW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q298blm2ds9bkeafz7yp.png" alt="Images as reported by the Network tab in Chrome developer tools" width="880" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our dev tools, we can see that images sizes are more reasonable as well:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wQEAskDu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktfbrrzgt7ak1nf3b3hc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wQEAskDu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktfbrrzgt7ak1nf3b3hc.png" alt="Mobile image sizes reported by Chrome developer tools" width="846" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we look in .next/cache/images we can also see the images that have been created:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eQPeYURF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mm9phc9a3qq57iok2mgc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eQPeYURF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mm9phc9a3qq57iok2mgc.png" alt="A list of the images created by next/image" width="880" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great, but we want to pull these images from our CMS or DAM. To do that, we need to tell next/image where we can get images from using the domains setting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const nextConfig = { 
  reactStrictMode: true, 
  images: { 
    loader: 'default', 
    domains: ['assets-us-01.kc-usercontent.com'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], 
    formats: ['image/webp'], 
  }, 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can update our image source for our remote image (in this case, coming from the assets in Kontent by Kentico).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className={styles.hero}&amp;gt;
  &amp;lt;Image layout="fill" alt="Styled photo of a retro microphone" className={styles.heroImage} src="https://assets-eu-01.kc-usercontent.com/36a6ba89-afdc-013f-dda5-806bb0d472c1/f125b960-fd12-42fb-8656-124600d6d61f/retro-mic.jpg" /&amp;gt;
  &amp;lt;h1 className={styles.title}&amp;gt; Welcome to &amp;lt;a href="https://nextjs.org"&amp;gt;Next.js!&amp;lt;/a&amp;gt; &amp;lt;/h1&amp;gt; 
  &amp;lt;p className={styles.description}&amp;gt; Get started by editing &amp;lt;code className={styles.code}&amp;gt;pages/index.js&amp;lt;/code&amp;gt; &amp;lt;/p&amp;gt; 
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we reload the application and look in the cache directory, we’ll see that images are yet again created with resized and optimised versions of our files. Given our CMS or DAM might already have the ability to resize images and may also have a globally distributed CDN, we can reduce the requests to our server and let the CDN do its works by adding a custom loader to the mix.&lt;/p&gt;

&lt;p&gt;Out of the box, the Image components default loaders support includes Vercel, Squoosh (default), Imgix, Cloudinary, and Akamai. Creating our own can be a simple task depending on what we need.&lt;/p&gt;

&lt;p&gt;We can add a really simple loader for Kontent by adding the following to index.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const kontentLoader = ({ src, width, quality }) =&amp;gt; { 
  return `${src}?w=${width}&amp;amp;q=${quality || 75}&amp;amp;auto=format` }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then make a small change to the image by adding &lt;code&gt;loader={kontentLoader}&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className={styles.hero}&amp;gt;
  &amp;lt;Image loader={kontentLoader} layout="fill" alt="Styled photo of a retro microphone" className={styles.heroImage} src="https://assets-eu-01.kc-usercontent.com/36a6ba89-afdc-013f-dda5-806bb0d472c1/f125b960-fd12-42fb-8656-124600d6d61f/retro-mic.jpg" /&amp;gt;
  &amp;lt;h1 className={styles.title}&amp;gt; Welcome to &amp;lt;a href="https://nextjs.org"&amp;gt;Next.js!&amp;lt;/a&amp;gt; &amp;lt;/h1&amp;gt;
  &amp;lt;p className={styles.description}&amp;gt; Get started by editing{' '} &amp;lt;code className={styles.code}&amp;gt;pages/index.js&amp;lt;/code&amp;gt; &amp;lt;/p&amp;gt; 
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we restart our app, we still see the images loading in the network tab of our dev tools, but nothing is being added to the cache folder, as the images are being requested directly from the source. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/docs/api-reference/next/image"&gt;next/image&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/docs/api-reference/next/image#loader-configuration"&gt;next/image loaders&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://kontent.ai/learn/reference/image-transformation/#a-working-with-the-image-urls"&gt;Kontent by Kentico - Image Transformations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>jamstack</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>kontent</category>
    </item>
    <item>
      <title>Using the REST Client in Visual Studio Code</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Mon, 09 Aug 2021 06:49:13 +0000</pubDate>
      <link>https://forem.com/mattnield/using-the-rest-client-in-visual-studio-code-344l</link>
      <guid>https://forem.com/mattnield/using-the-rest-client-in-visual-studio-code-344l</guid>
      <description>&lt;p&gt;Getting ready to test a new service or API for your project is a common requirement. Normally we’d just create something in PostMan or run a curl command straight from the terminal. But what if you could do something that becomes part of your project in source control instead, wouldn’t that be pretty neat? This is where the REST Client for Visual Studio Code comes in useful.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;REST Client extension&lt;/a&gt; by &lt;a href="https://twitter.com/HuachaoMao" rel="noopener noreferrer"&gt;Huachou Mao&lt;/a&gt; is a seemingly simple, yet powerful tool to have at your disposal when working in a service-oriented environment. It allows you to quickly make calls to an API endpoint, and to easily repeat those calls, all within &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I’ll describe how I came across the &lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;REST Client extension&lt;/a&gt;, how I use it in projects, and how I use it to try out new APIs.&lt;/p&gt;

&lt;p&gt;I first came across the REST Client plugin a few years ago at a &lt;a href="https://www.dotnetoxford.com/" rel="noopener noreferrer"&gt;.NET Oxford Meetup&lt;/a&gt; event. As I recall, the presenter was using it to quickly test their API endpoints, seeing the response in a new tab within Visual Studio Code. It was such a perfectly simple implementation that I went and installed it that night. It was impressive, but until recently, I’d been using &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; as my go-to tool for checking out REST API calls. It had served me well and I’d invested a lot of time in setting up collections, but recently, I wanted to make some changes to my setup.&lt;/p&gt;

&lt;p&gt;This is when I remembered the REST Client. The idea of being able to execute web requests quickly from my VS Code instance was an immediate pull. So I decided to investigate further to see if it would tick all the boxes.&lt;/p&gt;

&lt;p&gt;The question is, what were the boxes that I was trying to tick? I really wanted to achieve a couple of simple things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add my calls to source control. I don’t want to lose them, and I’ll more than likely run them more than once.&lt;/li&gt;
&lt;li&gt;Secure my API key. We don’t want those in source control!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Source Control
&lt;/h2&gt;

&lt;p&gt;So this one is simple. Once you've installed the plugin, you need to create and open a file in Visual Studio Code with a file extension of ‘.http’. Of course, once you get your API calls into source control, you need to take a look at one very important thing - API keys.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Securing API Keys
&lt;/h2&gt;

&lt;p&gt;Most of the APIs that I work with require authorization and that’s probably true in the majority of cases. Storing your key in a source repository (especially a public one) is not good practice. That gave me the conundrum of how I might make calls and not check those API keys into source control.&lt;/p&gt;

&lt;p&gt;If you consider the following API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://manage.kontent.ai/v2/projects/7af531c3-f4b9-4af6-8f9e-383f51ad3e4b/types &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer ew0KICAiYWxnIjogIkhTMjU214ZIiwNCiAgInR5cCI6ICJKV1QiDQp9.ew08KICAianRpIjogImJhYzhkODIxMzI1NTRlNGZiNGQxMGQ5MzAFYNhNDZlZmQyIiwNC629iAgImlhdCI6ICIxNjE5NzcwODE5IiwNCiAgImV4cCI6ICIxOTY1MzcwODE5IiwNCiAgInByb2plY3RfaWQiOiAiY2MzODBiODg1OTcwMDFiMzQzZjUwMmE3Y2FkNmU4NjIiLA0KICAidmVyIjogIjIuMS4wIiwNCiAgInVpZCBCI6ICJ1c3JfMHZPTjBVTDFBQ2ZVOXNyYjVUczQyWSIsDQogICJhdWQiOiAibWFuYWdlLmtlbnRpY29jbG91ZC5jb20iDQp9.4-gWmqdw7eybaZu3YkwgpoDieZr8zS2cKMOqBMX-t_E'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-type: application/json'&lt;/span&gt;

  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'
{
  "external_id": "article",
  "name": "Article",
  "codename": "article",
  "elements": [
    {
      "name": "Article title",
      "codename": "title",
      "type": "text"
    },
    {
      "name": "Article body",
      "codename": "body",
      "type": "rich_text"
    },
    {
      "name": "Author bio",
      "codename": "bio",
      "allowed_blocks": [
        "images",
        "text"
      ],
      "type": "rich_text"
    }
  ]
}’
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, it does what I need, but I really don’t want that authorization token stored in my source control, so what can we do about that?&lt;/p&gt;

&lt;p&gt;(don’t worry, the example keys above are invalid 🤓)&lt;/p&gt;

&lt;h2&gt;
  
  
  Variables and Environments
&lt;/h2&gt;

&lt;p&gt;This is where variables and environments come in with the REST Client extension. You can add new environments in your settings.json file to cater for this. As an example, I have the following in the project that I'm currently working on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"rest-client.environmentVariables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"$shared"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"b82a...yeah-not-the-real-key...3a62"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"preview_api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ew0K...yeah-not-the-real-key...UeMk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"management_api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ew0K...yeah-not-the-real-key...H4p0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"prod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db3f...yeah-not-the-real-key...a2f4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"preview_api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ew0K...yeah-not-the-real-key...68ZI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"management_api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ewto...yeah-not-the-real-key...oC3E"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These variables can now be used inline, so our initial API call now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://manage.kontent.ai/v2/projects/&lt;span class="o"&gt;{{&lt;/span&gt;project_id&lt;span class="o"&gt;}}&lt;/span&gt;/types &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer {{management_api}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-type: application/json'&lt;/span&gt;

  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'
{
  "external_id": "article",
  "name": "Article",
  "codename": "article",
  "elements": [
    {
      "name": "Article title",
      "codename": "title",
      "type": "text"
    },
    {
      "name": "Article body",
      "codename": "body",
      "type": "rich_text"
    },
    {
      "name": "Author bio",
      "codename": "bio",
      "allowed_blocks": [
        "images",
        "text"
      ],
      "type": "rich_text"
    }
  ]
}’
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's not only simpler to read, but those API keys are not stored in our file or the project as a whole, keeping them out of source control. &lt;/p&gt;

&lt;p&gt;When using the extension, these environments can be selected in VS code, making it easy to move between them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets-us-01.kc-usercontent.com%3A443%2F7ab511c8-f1e9-4ec7-869e-397f28ad4e3a%2F1f34f28e-bf2e-4f43-a602-fc75480dfc86%2FRESTClientEnvironment.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets-us-01.kc-usercontent.com%3A443%2F7ab511c8-f1e9-4ec7-869e-397f28ad4e3a%2F1f34f28e-bf2e-4f43-a602-fc75480dfc86%2FRESTClientEnvironment.gif" alt="Switching environments with the REST Client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping it all up
&lt;/h2&gt;

&lt;p&gt;The REST Client extension is a really useful tool to have at your disposal. In this article, I've really only scratched the surface of what it can do. It's well worth taking a few moments to look through the &lt;a href="https://github.com/Huachao/vscode-restclient" rel="noopener noreferrer"&gt;documentation in GitHub&lt;/a&gt; to find out what it's capable of.&lt;/p&gt;

&lt;p&gt;I can honestly say that this extension has saved me a lot of time and it's in my list of default extensions that I would recommend to anyone using VS Code.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>extension</category>
      <category>rest</category>
    </item>
    <item>
      <title>14 great free resources to help get you going fast with Kentico Kontent and .NET</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Tue, 30 Mar 2021 08:47:46 +0000</pubDate>
      <link>https://forem.com/mattnield/14-great-free-resources-to-help-get-you-going-fast-with-kentico-kontent-and-net-4mc5</link>
      <guid>https://forem.com/mattnield/14-great-free-resources-to-help-get-you-going-fast-with-kentico-kontent-and-net-4mc5</guid>
      <description>&lt;p&gt;How do you find the resources that your development team will need to get up and running with Kentico Kontent in .NET?&lt;/p&gt;

&lt;p&gt;Working with a headless CMS provides a number of benefits, one of which is the freedom to choose the technology stack that suits you. You might be making a choice based on your channel or perhaps based upon your in-house team's skillset. If you're heading into a new  &lt;a href="https://kontent.ai/"&gt;Kentico Kontent&lt;/a&gt;  project with a .NET team, where do you start?&lt;/p&gt;

&lt;h2&gt;
  
  
  Kontent Learning Resources
&lt;/h2&gt;

&lt;p&gt;Kentico Kontent has provided a good set of resources available to help you along your way. Most of this content can be accessed from either the Kentico Kontent site or from Kentico’s GitHub pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resource Centre
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kontent.ai/resources"&gt;https://kontent.ai/resources&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The resource centre is a great place to get started, with a plethora of webinars, white papers, ebooks, guides, videos, and more to set your team on the right path. Here you can look at things like approaches to content modelling, transitioning to microservices, or perhaps just seeing how others are getting on with things. It's not .NET focussed but looks at the wider product.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Community
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kentico.github.io/"&gt;https://kentico.github.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is more of a developer-focused resource in my mind. It is not restricted to Kentico Kontent as it also contains Kentico Xperience resources. You need to join this community through GitHub to get access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tutorial
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.kontent.ai/tutorials/develop-apps?tech=dotnet"&gt;https://docs.kontent.ai/tutorials/develop-apps?tech=dotnet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my opinion, this is the best of the .NET tutorials for developers who are just starting out. It is regularly updated as the platform updates, so by keeping the packages mentioned in this tutorial up to date, developers can very quickly create a simple application as a starting point to learn some of the basics and build up some core concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Resource Links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kentico.github.io/Home/RESOURCES"&gt;https://kentico.github.io/Home/RESOURCES&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2020, the Kentico MVP program split into two groups: Kentico Kontent and Kentico Xperience. Before that happened, the MVPs put together a list of useful links about each of the products. It contains links to a multitude of resources including social media accounts, blogs, user groups etc. as well as links to Kentico documentation, and partners.&lt;/p&gt;

&lt;h2&gt;
  
  
  .NET Core Kontent Delivery API &amp;amp; SDKs
&lt;/h2&gt;

&lt;p&gt;OK, so let's focus a little more on .NET. It's fair to say that the JavaScript world gets a lot of attention, but that does not mean to take anything away from the .NET stack. JavaScript has been the biggest uptake for Kentico Kontent for a while now, but there are still plenty of .NET resources that are available.&lt;/p&gt;

&lt;h3&gt;
  
  
  SDKs
&lt;/h3&gt;

&lt;p&gt;As mentioned, there are a few SDKs that wrap-up the APIs provided by the Kontent team. Broadly speaking there are three to consider:&lt;/p&gt;

&lt;h4&gt;
  
  
  The Delivery SDK
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/Kentico/kontent-delivery-sdk-net"&gt;https://github.com/Kentico/kontent-delivery-sdk-net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the most used SDK in .NET and provides the mechanisms for extracting information from Kentico Kontent to display in the application. You can also  &lt;a href="https://www.nuget.org/packages/Kentico.Kontent.Delivery/"&gt;download the Delivery SDK form NuGet&lt;/a&gt;  (this is preferred to pulling or forking from GitHub).&lt;/p&gt;

&lt;h4&gt;
  
  
  Content Management SDK
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/Kentico/kontent-management-sdk-net"&gt;https://github.com/Kentico/kontent-management-sdk-net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Content Management SDK is used to manipulate data in Kontent using the  &lt;a href="https://docs.kontent.ai/reference/management-api-v2"&gt;Management API&lt;/a&gt;. As an example, this can be used to migrate data, or even import content models into the Kontent project. Project structures can be documented in JSON and imported via the API or imported via code. At the moment, this is a little behind the JavaScript version of this SDK, with things like content types missing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Recommendations SDK
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/Kentico/kontent-recommendations-net/tree/vNext"&gt;https://github.com/Kentico/kontent-recommendations-net/tree/vNext&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Smart Recommendations SDK uses artificial intelligence (&lt;a href="https://www.recombee.com/"&gt;Recombee&lt;/a&gt;) to recommend relevant content to your visitors based on the content their content consumption and other similar journey's.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best practices for Delivery SDK for .NET
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Kentico/kontent-delivery-sdk-net/wiki"&gt;https://github.com/Kentico/kontent-delivery-sdk-net/wiki&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are some great tips here for not only working with Kentico Kontent in .NET, but also just working with .NET web apps in general. This is a resource that I don't believe many teams are aware of, but its full of some very useful practices that support a solid foundation for your projects. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  .NET Sample Applications
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Dancing Goat MVC
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/Kentico/kontent-sample-app-net"&gt;https://github.com/Kentico/kontent-sample-app-net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you know Kentico, then you know of Dancing Goat. 🐐 I think of it as Kentico's very on Contoso/Northwind. This is a more fully-formed Dancing Goat sample site. It goes further than the tutorials, though it's not e-commerce enabled unlike some of the Kentico Xperience Dancing Goat samples that Kentico have provided over the years.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dancing Goat Razor Pages
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/Kentico/kontent-sample-app-razorpages"&gt;https://github.com/Kentico/kontent-sample-app-razorpages&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another .NET implementation of Dancing Goat, this time using Razor Pages as the approach rather than MVC. This implementation is less polished than the MVC implementation, and perhaps not quite as useful, but if you're up razor pages it is a starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kontent Development Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  .NET Model Generator
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.nuget.org/packages/Kentico.Kontent.ModelGenerator/"&gt;https://www.nuget.org/packages/Kentico.Kontent.ModelGenerator/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Kentico Kontent model generator is a key tool when working with Kontent and .NET. It was developed to map the content types in your project into .NET classes that can be used with the .NET Delivery SDK. You can see this in both of the code examples above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backup Manager
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Kentico/kontent-backup-manager-js"&gt;https://github.com/Kentico/kontent-backup-manager-js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backup manager can provide the basis of the Kontent project migration; to import project structures and content via the Content Management API (CMAPI) and could possibly be used independently to create an internally managed/private set of project templates for Kentico Kontent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kontent Online Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Kontent Template Manager
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kentico.github.io/kontent-template-manager/"&gt;https://kentico.github.io/kontent-template-manager/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Kontent Template Manager allows for the import and export of a project from Kentico Kontent. Exports will take all the content type structure and data and export them to a single ZIP archive. This archive can then be imported into another project and used as a template.&lt;/p&gt;

&lt;p&gt;As the name suggests, there are also templates here. A template is made up of application source files and a ZIP file containing the content for the application. There are a few to choose from, four of which are on the .NET stack.&lt;/p&gt;

&lt;p&gt;To use this tool, the projects need to have the Management API enabled in the project settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment Comparer
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Simply007/kontent-environments-comparer"&gt;https://github.com/Simply007/kontent-environments-comparer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built by  &lt;a href="https://ondrej.chrastina.tech/"&gt;Ondřej Chrastina&lt;/a&gt;, the environment comparer is a great tool that will allow you to select two different environments to compare. The output is a git-styled diff of all of the content types in your project. This really useful when trying out changes quickly in Kontent using environments and provides a pointer to the scripts needed for the CLI in order to create a new migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What isn't in .NET?
&lt;/h2&gt;

&lt;p&gt;As I mentioned above, javascript especially has a lot of traction and support when it comes to Kentico Kontent. As a result, there are still a number of places where developers might need to brush up on their JavaScript. For me the two main areas here are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Custom Elements&lt;/strong&gt;. These allow you to extend the Kontent user interface to add your own field type and integrations (i.e. a YouTube video selector). You require some JS to put these together as they need to interact with the DOM and the Kontent application.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Kontent CLI&lt;/strong&gt;. Most developers will tell you that being able to script things makes them happy. This is because a script is less susceptible to typos and - more often than not - 100% repeatable. Being able to create and update a project on the command-line is a must for any serious project of scale. If your team want this, then they'll need either JavaScript or TypeScript skills.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  So, what next?
&lt;/h2&gt;

&lt;p&gt;If you need to get your team up to speed, then I hope the above has given you something useful to look at. If I were to suggest my top two things to look at, it would be  &lt;a href="https://github.com/Kentico/kontent-delivery-sdk-net/wiki"&gt;Best practices for Delivery SDK for .NET&lt;/a&gt;, and the  &lt;a href="https://kontent.ai/resources"&gt;Resource Center&lt;/a&gt;. These two give a good balance between technical and more business-oriented knowledge, which can give you more confidence as you move forward.&lt;/p&gt;

</description>
      <category>kenticokontent</category>
      <category>cms</category>
      <category>webdev</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Returning to .NET</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Thu, 11 Mar 2021 09:26:58 +0000</pubDate>
      <link>https://forem.com/mattnield/returning-to-net-1nb1</link>
      <guid>https://forem.com/mattnield/returning-to-net-1nb1</guid>
      <description>&lt;p&gt;I've had a website built in Gatsby for a while now, but I really did miss having it in .NET. Here's how and why I moved to a .NET static-site instead of Gatsby.&lt;/p&gt;

&lt;p&gt;Just over a year ago, I rebuilt my personal website in  &lt;a href="https://www.gatsbyjs.com/"&gt;Gatsby.js&lt;/a&gt;. Having maintained that for a while now, I wanted to move back to .NET, so I'd like to share how that project worked out.&lt;/p&gt;

&lt;p&gt;I don't create new content on an hourly basis, so for me having a server-rendered site doesn't really make much sense. Up-to-date means that when I publish some content, it appears on my site and stays there until something new comes along. At the time I was on my journey into the world of Gatsby, I was in the mindset of someone who had heard great things about JAMStack and wanted to try it out. That's what I decided to do one day on the train into London.&lt;/p&gt;

&lt;p&gt;Rather than just blindly hacking away until I had a new site though, I set myself a few goals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; 🚀 Create a site that was blazingly fast.&lt;/li&gt;
&lt;li&gt; 💰 Reduced hosting costs.&lt;/li&gt;
&lt;li&gt; 🚫 No changes to my content model.&lt;/li&gt;
&lt;li&gt; 🎓 Learn something new.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can read about  &lt;a href="https://www.mattnield.co.uk/blog/moving-from-asp-net-core-to-gatsby/"&gt;my experience of moving to Gatsby&lt;/a&gt;  in my earlier post, but the key point is that all four of those boxes got ticked, and I ended up with a site that I was reasonably pleased with. (I must point out that I'm no designer, so while the design might have been lacking, I was pleased with how it was put together behind the scenes). My one gripe was that I'm still a .NET developer/fan and I did feel a little naughty building a site in JavaScript! 😳&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I rebuilt in .NET
&lt;/h2&gt;

&lt;p&gt;Back in November 2020 (yes, that year), this tweet from  &lt;a href="https://ondrej.chrastina.tech/"&gt;Ondrej Chrastina&lt;/a&gt;  caught my attention:&lt;/p&gt;

&lt;p&gt;Technology moves fast, and more recently we've seen  &lt;a href="https://statiq.dev/"&gt;Statiq&lt;/a&gt; appear on the scene. Statiq is a .NET site generator created by  &lt;a href="https://daveaglick.com/"&gt;Dave Glick&lt;/a&gt;  (yes, the brains behind the  &lt;a href="https://wyam.io/"&gt;Wyam&lt;/a&gt;  project). This gave me an opportunity to think about how I might be able to get back to .NET and keep my static site .&lt;/p&gt;

&lt;p&gt;For a while, I just played around with the  &lt;a href="https://github.com/alanta/Kontent.Statiq"&gt;Kontent.Statiq module&lt;/a&gt;  and my Kontent project, but ultimately decided that - given I needed to make my site look nice - Statiq was a nice opportunity to learn something new while making some much-needed improvements to my site.&lt;/p&gt;

&lt;p&gt;So great - what were my goals for creating a new site:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; 🤓 It  &lt;em&gt;has&lt;/em&gt; to be in .NET&lt;/li&gt;
&lt;li&gt; 🚀 Still needs to be really fast, so basically still static.&lt;/li&gt;
&lt;li&gt; 💰 Still needs to be low-cost/no-cost hosting.&lt;/li&gt;
&lt;li&gt; 👁 It has to not look terrible.&lt;/li&gt;
&lt;li&gt; 🎓 It needs to teach me something new.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Blazingly fast with .NET
&lt;/h3&gt;

&lt;p&gt;Points 1 and 2 were solved by using Statiq. There are more reasons than just speed for having a static site, but for now, my focus was speed. My speed benefit turned out to be a bit more than I was expecting. Being more familiar/comfortable with .NET, I was simply coding quicker with Statiq. There was definitely a learning curve involved, but it was nowhere near that which I'd experienced with picking up Gatsby. Being honest, I did miss the simplicity of GraphQL. My build times pipelines actually run similar times on both .NET and npm, they're within a few seconds. The biggest gain was probably the final file size. I reduced the overall size of the pages as there was less involved. For the most part, I'm just rendering HTML - sure there is some JavaScript involved for the menu toggle etc, but other than that, it is truly static.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting on the cheap
&lt;/h3&gt;

&lt;p&gt;Hosting was an issue for me. I really wanted to use  &lt;a href="https://docs.microsoft.com/en-us/azure/static-web-apps/"&gt;Azure Static Web Apps&lt;/a&gt;, but two things were a bit annoying. The first thing was that I needed to use  &lt;a href="https://docs.github.com/en/actions"&gt;GitHub Actions&lt;/a&gt;  to deploy (given it's still in beta), and my thoughts at the time were that I wanted to use Azure DevOps. From what I can see, Microsoft does not support that in the beta (which seems like an odd choice and makes me wonder how long Azure DevOps is going to be around). The second was that kicking off a GitHub action from a  &lt;a href="https://docs.kontent.ai/reference/webhooks-reference"&gt;Kontent webhook&lt;/a&gt;  wasn't as straight forward as it is in  &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;  and I'm was looking for a simple solution.&lt;/p&gt;

&lt;p&gt;So, off I went building a new Pipeline in Azure DevOps that would publish to Netlify. This worked, it wasn't fast, but it worked. While I then started to look at triggering the build from the Kontent webhook, I came across something I didn't know at the very end of an article on the Netlify blog written by the Kontent developer relations team about  &lt;a href="https://www.netlify.com/blog/2021/01/22/why-should-.net-developers-be-interested-in-jamstack/"&gt;why .NET developers should be interested in JAMStack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Simply put, Netlify can do .NET Core builds now - amazing! 🥳. So my build went from a fairly average YML file to a simple  &lt;code&gt;dotent run&lt;/code&gt;  command. I don't know when this became possible in Netlify, but I'm really happy that it did. .NET 5 is included on the default build image and performs better than my build pipeline on Azure DevOps.&lt;/p&gt;

&lt;p&gt;That's hosting sorted and the third point checked off, I just stay on Netlify.&lt;/p&gt;

&lt;p&gt;I will point out that I'm super happy with the free version of Netlify. It gives me plenty of build minutes (my build is less than 60 seconds) and my personal use of the data fits well within the limits. If you're doing this commercially though, it's well worth paying for the service to ensure that you have the number of build minutes that you need for preview etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making it look pretty
&lt;/h3&gt;

&lt;p&gt;The look and feel was my next item. Now, this doesn't really have much to do with my choice of .NET. If I had stuck with Gatsby, I would have been addressing my somewhat lacking visual design anyway.&lt;/p&gt;

&lt;p&gt;As I said, I'm no designer, and while I was enjoying exploring what I could do with CSS and UX, it really wasn't doing anyone else any favours. 😳 I needed something simple for my site that was clean and accessible. Rather than try again to build something from scratch. I conceded that I really needed a template and so I ended up choosing the  &lt;a href="https://html5up.net/alpha"&gt;Alpha template from html5up.com&lt;/a&gt;  for this. If you visit HTML5Up, you'll find some awesome templates that you can use to start your projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  I'm always learning
&lt;/h3&gt;

&lt;p&gt;.NET has been my choice for building web applications since it's initial release back in 2002. In recent years - and especially with .NET Core - it feels like things have been moving much faster. Newer C# language features have a more functional feel to them, and this can change the way that we approach code.&lt;/p&gt;

&lt;p&gt;The approach that Statiq uses isn't one that I'd used extensively and was something that I was keen to practice more. Statiq uses pipelined and modules to process content, with each module being immutable and essentially taking in some metadata and outputting some metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MyqfyFjk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://preview-assets-us-01.kc-usercontent.com/7ab511c8-f1e9-4ec7-869e-397f28ad4e3a/ee4bb7bb-c1c6-461a-9cd4-b6d9b4c99376/statiqflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MyqfyFjk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://preview-assets-us-01.kc-usercontent.com/7ab511c8-f1e9-4ec7-869e-397f28ad4e3a/ee4bb7bb-c1c6-461a-9cd4-b6d9b4c99376/statiqflow.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It sure takes some getting used to, but once you break into that idea that it's all just metadata things really fall into place quickly. So in picking up Statiq, that checks off the last goal of learning something new. Do I know it inside-out? No, but the more I use it the more I like it.&lt;/p&gt;

&lt;p&gt;As an added bonus on the learning front, I used the  &lt;a href="https://github.com/Kentico/kontent-cli#kentico-kontent-cli"&gt;Kentico Konent CLI&lt;/a&gt;  to manage the changes in my content types. I made some changes to my content model as part of this project. I made the changes and previewed the site in a  &lt;a href="https://docs.kontent.ai/tutorials/manage-kontent/projects/manage-environments"&gt;separate environment within Kontent&lt;/a&gt;, and in order to put these changes live without the risk of me making a terrible typo, I opted to script the changes. The process of doing that was simple and is definitely something I will be doing again in my upcoming projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Did it work?
&lt;/h2&gt;

&lt;p&gt;Yes, completely. In this project, I managed to build a site that achieved all of the goals that I'd set. Even while I'm writing this, I know I have  &lt;em&gt;more&lt;/em&gt;  that I want to add to this project. For now, I've replaced my website with something that I can easily maintain, builds quickly, has a small footprint, and ultimately puts me back in .NET.&lt;/p&gt;

&lt;p&gt;Is this site a JAMStack site? No, not  &lt;em&gt;yet.&lt;/em&gt;  There is still more to come, but if you subscribe to the notion that a JAMStack site must be static, then this is clearly headed in the right direction.&lt;/p&gt;

</description>
      <category>kenticokontent</category>
      <category>cms</category>
      <category>jamstack</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using Kentico Kontent in LINQPad</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Thu, 25 Feb 2021 15:37:31 +0000</pubDate>
      <link>https://forem.com/mattnield/using-kentico-kontent-in-linqpad-56m7</link>
      <guid>https://forem.com/mattnield/using-kentico-kontent-in-linqpad-56m7</guid>
      <description>&lt;p&gt;Sometimes you simply want to try out some code without having to go through the ceremony of setting up a project. Using tools like &lt;a href="https://www.linqpad.net/"&gt;LINQPad&lt;/a&gt; can help by providing you with a quick way to run .NET small queries and programs in isolation, with a really powerful set of methods to output the object graphs to a results window.&lt;/p&gt;

&lt;p&gt;I use LINQPad a lot, and most recently with the &lt;a href="https://kontent.ai/?utm_source=KONTENT_LINQPAD&amp;amp;utm_medium=mvp_406111&amp;amp;utm_campaign=extended_trial"&gt;Kentico Kontent&lt;/a&gt; headless CMS. Kontent has a set of &lt;a href="https://docs.kontent.ai/tutorials/develop-apps/get-started/sdks?tech=dotnet"&gt;.NET SDK&lt;/a&gt; which wraps it's API and makes it super easy to use as a .NET developer.&lt;/p&gt;

&lt;p&gt;In this video, I'll introduce LINQPad and show you how I use it with Kentico Kontent.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/j1DpsuoxfZ4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>cms</category>
      <category>kenticokontent</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Using Preview in Kentico Kontent on your Local Development Site</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Wed, 30 Sep 2020 10:34:23 +0000</pubDate>
      <link>https://forem.com/mattnield/using-preview-in-kentico-kontent-on-your-local-development-site-1fi0</link>
      <guid>https://forem.com/mattnield/using-preview-in-kentico-kontent-on-your-local-development-site-1fi0</guid>
      <description>&lt;p&gt;With a lot of teams working remotely, being able to share what you're working on with your team easily is increasingly important. If you're working on some new features for a project, you don't really want to screen share whenever another team member needs to check out your progress. You also don't want to push something into source control just so that your CI pipeline produces a new version of your app from someone them to view.&lt;/p&gt;

&lt;p&gt;Lets assume your project is a website and you're working on adding an e-commerce capability - this is brand new work and there is nothing like it on your existing website. How can you let your colleagues see your new changes to the website? Well, if you're working Kentico Kontent allows you to have &lt;strong&gt;Preview URLs&lt;/strong&gt; setup in your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Preview URLs?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.kontent.ai/tutorials/write-and-collaborate/preview-content/preview-unpublished-content" rel="noopener noreferrer"&gt;&lt;strong&gt;Preview URLs&lt;/strong&gt;&lt;/a&gt; allow you to provide a different URL structure for each content type. These URLs expose a couple of macros to allow key identifiers from your content to be added to your URL. This includes the URL slug, language variant, the codename and the ID of a content item.&lt;/p&gt;

&lt;p&gt;So on our site for example, a preview URL for a product might be as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/products/{Codename}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the preview URL is publicly available, then anyone who has access can see it. With a local development environment you need to create a 'tunnel' in order to be able to give someone outside your home or office network access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a tunnel to your environment
&lt;/h2&gt;

&lt;p&gt;In order to create a tunnel to the development environment, we're going to use a service called &lt;a href="https://ngrok.io" rel="noopener noreferrer"&gt;&lt;strong&gt;ngrok&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ngrok&lt;/strong&gt; is an application that exposes your local development server through a secure tunnel via the &lt;em&gt;ngrok&lt;/em&gt; cloud service. The tunnel is exposed via a URL on a subdomain of &lt;code&gt;ngrok.io&lt;/code&gt;. The &lt;em&gt;ngrok&lt;/em&gt; application on your local machine then forwards the request to your local development server and returns the response back to the service. The short story being that you can expose your local development machine over the net to anyone who wants/needs to see it. It also gives some nice features like being able to see all requests and responses, as well as re-running requests as needed (which is great for testing).&lt;/p&gt;

&lt;p&gt;Using the .NET boilerplate template for Kentico Kontent and performing a &lt;code&gt;dotnet run&lt;/code&gt; will start up a local server and make it available on the following two bindings by default:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Port 5000 for HTTP (&lt;code&gt;http://localhost:5000&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Port 5001 for HTTPS (&lt;code&gt;https://localhost:5001&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we test out site, we really want to be using HTTPS, so we'll want to tell &lt;em&gt;ngrok&lt;/em&gt; to use that port number. In order to specify a port number, we need a signed-up account with &lt;em&gt;ngrok&lt;/em&gt;. That doesn't cost us anything as long as we can accept the random generated subdomain. In our case this is fine, but upgrading to the basic plan with &lt;em&gt;ngrok&lt;/em&gt; will allow you to use a fixed sub-domain.&lt;/p&gt;

&lt;p&gt;To illustrate this, I make a screen capture of me running a .NET application from the command line and then making this accessible on the web.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zmafwsUbL9g"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As you can see from the above video, to create the tunnel we just need to run the following command from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http https://localhost:5001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This then lists out the URLs that the &lt;em&gt;ngrok&lt;/em&gt; service is listening for. We can take the HTTPS URL and then add this to the Preview URL settings in Kentico Kontent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating Kentico Kontent
&lt;/h2&gt;

&lt;p&gt;Updating Kentico Kontent with the required URLs is as simple as navigating to the project settings and modifying the URLs for the content types that you want to preview.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm100geuzizwgsbuj8uer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm100geuzizwgsbuj8uer.png" alt="Preview URL settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once this has been set, Kentico Kontent will allow you to click the preview URL button, which will open the page in a new tab/window in your browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fejya06hle5ovn08ssvl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fejya06hle5ovn08ssvl8.png" alt="Preview URL Button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick summary
&lt;/h2&gt;

&lt;p&gt;You can use &lt;em&gt;ngrok&lt;/em&gt; to expose your local development environment in order to give access to other members of your team. By adding the addresses to the Preview URL configuration for your project/feature environment in Kentico Kontent you can enable other project members to see your work using the &lt;a href="https://kontent.ai/" rel="noopener noreferrer"&gt;Kentico Kontent&lt;/a&gt; administration interface with minimal effort. 💪&lt;/p&gt;

&lt;p&gt;The setup here is pretty simple, but it can work to facilitate collaboration during the early phases of a project where you really are not ready to push anything up to your build server. It's worth noting that the same principal also exists for web hooks. I you want to test that your cache is correctly flushed or debug that the Azure Function that you're working on, &lt;em&gt;ngrok&lt;/em&gt; can be a great help. &lt;/p&gt;

&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;p&gt;This article has shown how to set up basic preview URLs in your Kentico Kontent project on your local development environment using &lt;em&gt;ngrok&lt;/em&gt; to give access to remote team members. Given our level of remote working in 2020 😷, that's a pretty useful thing to have set. But this is not the end of the story. In September 2020, Kentico Kontent also released the &lt;a href="https://webspotlight.kontent.ai/" rel="noopener noreferrer"&gt;&lt;strong&gt;Web Spotlight&lt;/strong&gt;&lt;/a&gt; feature, which closes the gap between a headless CMS and the desire of marketers and content editors to be able to easily and visually maintain and create content. I'm really excited about Web Spotlight, but sadly have not used it yet, so that is my next project 😃&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cover photo by &lt;a href="https://unsplash.com/@thoughtcatalog?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Thought Catalog&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>kenticokontent</category>
      <category>cms</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating a .gitignore file using the .NET Core SDK</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Wed, 16 Sep 2020 21:01:45 +0000</pubDate>
      <link>https://forem.com/mattnield/building-up-your-content-model-39bo</link>
      <guid>https://forem.com/mattnield/building-up-your-content-model-39bo</guid>
      <description>&lt;p&gt;I recently saw a tweet from fellow Kentico MVP &lt;a href="https://twitter.com/mcbeev" rel="noopener noreferrer"&gt;Brian McKeiver&lt;/a&gt; about creating a &lt;code&gt;.gitignore&lt;/code&gt; file using the .NET SDK. His question being why he'd not known it was a thing before now. Well, neither had I, and I wanted to take a look at it as it sounds like quite a time/life saver.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1305876595249483776-179" src="https://platform.twitter.com/embed/Tweet.html?id=1305876595249483776"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1305876595249483776-179');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1305876595249483776&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;So, when did this become a thing? Looking at the &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new" rel="noopener noreferrer"&gt;.NET Core SDK documentation&lt;/a&gt;, we can see that back in September of 2019, Microsoft release the 3.0 SDK. This obviously had quite alot of additions, and some of those were some new templates for the &lt;code&gt;dotnet new&lt;/code&gt; command. &lt;/p&gt;

&lt;p&gt;The list of additional features in 3.0 is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WPF Application&lt;/li&gt;
&lt;li&gt;WPF Class library&lt;/li&gt;
&lt;li&gt;WPF Custom Control Library&lt;/li&gt;
&lt;li&gt;WPF User Control Library&lt;/li&gt;
&lt;li&gt;Windows Forms (WinForms) Application&lt;/li&gt;
&lt;li&gt;Windows Forms (WinForms) Class library&lt;/li&gt;
&lt;li&gt;Worker Service&lt;/li&gt;
&lt;li&gt;Razor Component&lt;/li&gt;
&lt;li&gt;Blazor Server App&lt;/li&gt;
&lt;li&gt;ASP.NET Core gRPC Service&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dotnet gitignore file&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Dotnet local tool manifest file&lt;/li&gt;
&lt;li&gt;Protocol Buffer File&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously the one that I care about here is &lt;code&gt;dotnet gitignore file&lt;/code&gt;. It's a realy easy command to use, but it can save you from some of the basic mistakes when creating an new project.&lt;/p&gt;

&lt;p&gt;Running the command just consists of the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are no other options here, what you're going to get is a fairly comprehensive &lt;code&gt;.gitignore&lt;/code&gt; (I've listed it out at the end of this article). In terminal, you'll see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc2c5lx84qzewz0f6gd53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc2c5lx84qzewz0f6gd53.png" alt="running the command to create a new .gitignore file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typically you'll have a .gitignore file that you might copy and paste from project to project, or you might build it up as you go along. The later of those two option is always more prone to error, so being able to create this as a starter is certainly going to be helpful for that next new project!&lt;/p&gt;

&lt;h3&gt;
  
  
  The generated &lt;code&gt;.gitignore&lt;/code&gt; file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup &amp;amp; report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

##
## Visual studio for Mac
##


# globs
Makefile.in
*.userprefs
*.usertasks
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.tar.gz
tarballs/
test-results/

# Mac bundle stuff
*.dmg
*.app

# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

# JetBrains Rider
.idea/
*.sln.iml

##
## Visual Studio Code
##
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>git</category>
      <category>dotnetcli</category>
    </item>
    <item>
      <title>How to ensure you have the right security headers</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Wed, 20 May 2020 08:08:56 +0000</pubDate>
      <link>https://forem.com/mattnield/how-to-ensure-you-have-the-right-security-headers-3nkm</link>
      <guid>https://forem.com/mattnield/how-to-ensure-you-have-the-right-security-headers-3nkm</guid>
      <description>&lt;p&gt;&lt;strong&gt;Security headers - loved by security teams and loathed by developers. They tell the consumers of your web application what to expect and what it can do. The question is, how can you ensure that your application has the right headers set?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I find myself getting more involved in headless CMS development these days. My choice of platform is &lt;a href="https://kontent.ai/"&gt;Kentico Kontent&lt;/a&gt;, and I've been building static sites using &lt;a href="https://www.gatsbyjs.com/"&gt;Gatsby&lt;/a&gt;.  I found that a large number of sites built this way do not have security headers set. For me, part of a go-live checklist needs to ensure that your application keeps you, your customers and your organisation safe. A good step forward here is setting the security headers on your site.&lt;/p&gt;

&lt;p&gt;Let's take a quick look at what security headers are and then take a look at how we can set them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we need security headers
&lt;/h2&gt;

&lt;p&gt;We use security headers to inform the browser of the expectations of our application. This covers things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what external data and script sources we intend to use&lt;/li&gt;
&lt;li&gt;how our application can present itself&lt;/li&gt;
&lt;li&gt;what features of the device our application interacts with&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These headers help to keep our application, data, and users safe from attacks. Most of the headers in this article address cross-site scripting (XSS). XSS is the term used when injecting harmful code into an application.&lt;/p&gt;

&lt;p&gt;A common requirement of any web application project is to engage the services of a 3rd party to perform penetration or ‘pen’ testing on your application. One of the first things that will be tested for is the security headers. This goes hand-in-hand with the commonly seen ‘Top 10’ from OWASP. As a result, there is a dedicated &lt;a href="https://owasp.org/www-project-secure-headers/"&gt;OWASP security headers project&lt;/a&gt; that gives a good level of detail.&lt;/p&gt;

&lt;p&gt;But why is this important if you're generating a static site? It depends on what your site (or application) does. As you add external services for customer reviews, contact forms, and eCommerce integration etc., we increase the number of possible vulnerabilities of the application. It may be true that your core data is on accessed when you rebuild your application, but all of those other features added can leave you, your customers, and your organisation exposed. Being frank, even if you &lt;em&gt;don't&lt;/em&gt; add external services there is a risk. This risk is easily reduced using some basic security headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which headers should you include?
&lt;/h2&gt;

&lt;p&gt;Typically you want to cover off as many of these as possible. There is however no value in setting a security header in a completely insecure manner. In those instances, I would say that the header can be and probably should be excluded.&lt;/p&gt;

&lt;p&gt;The OWASP list of security headers is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#http-strict-transport-security-hsts"&gt;HTTP Strict Transport Security (HSTS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#public-key-pinning-extension-for-http-hpkp"&gt;Public Key Pinning Extension for HTTP (HPKP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#x-frame-options"&gt;X-Frame-Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#x-xss-protection"&gt;X-XSS-Protection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#x-content-type-options"&gt;X-Content-Type-Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#Content-Security-Policy"&gt;Content-Security-Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#x-permitted-cross-domain-policies"&gt;X-Permitted-Cross-Domain-Policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#referrer-policy"&gt;Referrer-Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#expect-ct"&gt;Expect-CT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-secure-headers/#feature-policy"&gt;Feature-Policy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For our purposes, I have chosen a few of the headers that make the most impact concerning XSS. The following three headers are those that get a little more press and are more essential when it comes to application security.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content-Security-Policy (CSP)
&lt;/h3&gt;

&lt;p&gt;The CSP is one of the stronger ways to protect your application against XSS. In a nutshell, it whitelists sources of approved content for use in your application. The CSP instructs the browser not to load any other content sources in our application.&lt;/p&gt;

&lt;p&gt;This is quite a powerful header and is difficult to set up for web applications. It's common for a web application to use many content sources to provide functionality, content, and UI flare. It's tricky because you can set the following directives comprehensively. The list can be found on the Mozilla developer site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conveniently, any directive not set, the browser will use the default-src value.&lt;/p&gt;

&lt;p&gt;There are a couple of things to note about CSP (which is why it appears more complex):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unlike some other headers, you can only set the CSP header once. Whichever is the last one read by the browser is the one which will be used.&lt;/li&gt;
&lt;li&gt;Inline script and styles fall foul of this and require you either set unsafe-inline or perform a bit of additional logic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Catering for inline scripts and styles needs you to create a hash of the content. It’s mostly a simple thing to do. Chrome makes it quite easy to understand with a helpful message in the console (in this case for &lt;code&gt;&amp;lt;script&amp;gt;alert('Hello, world.')&amp;lt;/script&amp;gt;&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--11B6Ez4L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fhsuk6q3dgrkykjvtldg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--11B6Ez4L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fhsuk6q3dgrkykjvtldg.png" alt="Chrome console message for inline script"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’re given the has that we need to add as &lt;code&gt;'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng='&lt;/code&gt;. But you can do the following in at the comment line too if you want to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"alert('Hello, world.');"&lt;/span&gt; | openssl dgst &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-binary&lt;/span&gt; | openssl enc &lt;span class="nt"&gt;-base64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're unsure what your CSP needs to contain, you can instead use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only"&gt;&lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt;&lt;/a&gt; header. For this, you provide your anticipated directives and an endpoint to collect violations. This allows you to build an accurate set of directives before they are applied. This can be especially useful when using 3rd party sources such as Google Tag Manager that may inject content from multiple sources. &lt;/p&gt;

&lt;p&gt;For the rest of this article, this is the header I will focus on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feature-Policy
&lt;/h3&gt;

&lt;p&gt;Feature Policy allows us to specify which web platform features our application can and cannot use. This caters for vibrate events, camera use and microphone use. The full list of things you can control is extensive and can be found on the Mozilla developer site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
Strict-Transport-Security&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Often referred to as HSTS, this header instructs the user agent to enforce the use of HTTPS, strengthening your implementation of TLS. Under the hood, the purpose of this header is to remind the user agent that this site should be accessed on HTTPS. &lt;/p&gt;

&lt;p&gt;The common example is accessing your usual internet banking from a public WiFi location. So long as you’ve been on your bank’s website from a secure location (and HSTS was set), the user agent will know that the site should be accessed over HTTPS. This means that if the public WiFi is compromised in some way, the user agent will not accept the non-HTTPS connection.&lt;/p&gt;

&lt;p&gt;As a bonus, because the user agent knows that the application needs to be served over HTTPS, unnecessary 301 redirects for non-HTTPS versions of the application can be avoided.&lt;/p&gt;

&lt;h3&gt;
  
  
  X-Frame-Options
&lt;/h3&gt;

&lt;p&gt;The X-Frame-Options header instructs the user agent whether you want to allow your site to be framed or not. Preventing the application being embedded in a frame you can help to reduce the likelihood of &lt;a href="https://www.troyhunt.com/clickjack-attack-hidden-threat-right-in/"&gt;clickjacking&lt;/a&gt; attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to set the headers
&lt;/h2&gt;

&lt;p&gt;How you build and host your application has a great influence on how you set the security headers. Different hosting providers have different ways to set headers at an application level, and different stacks give you different options too. I.e JAMSTack vs. .NET Core.&lt;/p&gt;

&lt;p&gt;Here I’ll touch on how to set these headers in a Gatsby application hosted in &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;. As an additional bonus, I presented this topic recently at a .NET meetup, so there are some examples for .NET too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting in HTML
&lt;/h3&gt;

&lt;p&gt;One of the simplest methods of setting HTTP response headers for a web page is to add them into the head of the HTML document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt; 
      &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"script-src 'self';
               style-src 'self';
               image-src ‘self;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;http-equiv&lt;/code&gt; instructs the user agent to use the supplied content as an HTTP response header. What I've noticed with this in Chrome is that it does not always pick up correctly. You'll still get console notifications if your CSP header is incorrectly set, but it will not necessarily show up in the Network tab when you view the document headers.&lt;/p&gt;

&lt;p&gt;This approach also allows you to set individual values for each page, rather than applying the same value across the entire application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting headers in Gatsby.js
&lt;/h3&gt;

&lt;p&gt;When we think about static site generators like Gatsby, we look at separation from the data source and decide that they are secure, as there is no access to the source data. In reality, we add forms and connect other services to create a more rounded application. So for example adding FormStack or Snipcart to our application to add contact forms or e-commerce capabilities.&lt;/p&gt;

&lt;p&gt;There are several options available with static sites, and some of them depend on where you are hosting your application.&lt;/p&gt;

&lt;p&gt;From the CSP perspective, you can add the &lt;a href="https://www.gatsbyjs.org/packages/gatsby-plugin-csp"&gt;&lt;code&gt;gatsby-plugin-csp&lt;/code&gt;&lt;/a&gt; plugin. This plugin allows you to configure the common parts of the CSP header, but also can automatically add in the hashes for inline components as your application is built. &lt;/p&gt;

&lt;p&gt;As an example, here's the &lt;code&gt;gatsby-plugin-csp&lt;/code&gt; configuration (in &lt;code&gt;gatsby-config.js&lt;/code&gt;) that I was experimenting with for my site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;resolve:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`gatsby-plugin-csp`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;options:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;disableOnDev:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;mergeScriptHashes:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;mergeStyleHashes:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;mergeDefaultDirectives:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;directives:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"default-src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"'self' https:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"script-src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"'self' 'unsafe-inline' https:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"style-src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"'self' 'unsafe-inline' https: blob: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"img-src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"'self' data: https:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"font-src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"'self' data: https:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is that - as above - the CSP header is added as an &lt;code&gt;http-equiv&lt;/code&gt; as shown above. In reality, the above example allows anything so long as it's HTTPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the &lt;code&gt;_headers&lt;/code&gt; file
&lt;/h3&gt;

&lt;p&gt;Netlify uses a file to specify the headers that can be applied to the applications that it hosts. This file is named &lt;code&gt;_headers&lt;/code&gt; and sits in the publish directory of your site.&lt;/p&gt;

&lt;p&gt;When I use this file, I place it in my &lt;code&gt;static&lt;/code&gt; folder. Typically, I use a fairly simple file, but it can become more complex if you need it to. Here's an example from a site I've been working on recently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
  X-Frame-Options: SAMEORIGIN
  X-XSS-Protection: 1; mode=block
  X-Content-Type-Options: nosniff
  Content-Security-Policy: default-src 'self' https://*.kc-usercontent.com https://*.google-analytics.com; font-src data:; style-src 'self' 'unsafe-inline' https://*.googletagmanager.com; script-src 'self' 'unsafe-inline' https://*.googletagmanager.com https://*.google-analytics.com
  Referrer-Policy: strict-origin-when-cross-origin
  Feature-Policy: geolocation 'self'
  Feature-Policy: midi 'self'
  Feature-Policy: notifications 'self'
  Feature-Policy: push 'self'
  Feature-Policy: sync-xhr 'self'
  Feature-Policy: microphone 'self'
  Feature-Policy: camera 'self'
  Feature-Policy: magnetometer 'self'
  Feature-Policy: gyroscope 'self'
  Feature-Policy: speaker 'self'
  Feature-Policy: vibrate 'self'
  Feature-Policy: fullscreen 'self'
  Feature-Policy: payment 'self'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.netlify.com/routing/headers/#syntax-for-the-headers-file"&gt;Read about setting custom headers in Netlify&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting headers in ASP.NET Core
&lt;/h3&gt;

&lt;p&gt;There are a number of places that you can add security headers in ASP.NET. First, you could add them in the application configuration itself by adding the following in&lt;code&gt;startup.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"script-src 'self'; "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"style-src 'self'; "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"img-src 'self'"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This policy simply stated that any scripts, styles, or image must come from the same origin as the application. This is going to apply the header to all requests to the application.&lt;/p&gt;

&lt;p&gt;Another approach is to use the &lt;code&gt;web.config&lt;/code&gt; file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;httpProtocol&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;customHeaders&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"script-src 'self'; style-src 'self'; img-src 'self'; "&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;/customHeaders&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/httpProtocol&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, this approach will add the same CSP to all requests tot he application.&lt;/p&gt;

&lt;p&gt;There are also external libraries that you can use to control security headers. A great example is &lt;a href="https://github.com/juunas11/aspnetcore-security-headers"&gt;&lt;code&gt;aspnetcore-security-headers&lt;/code&gt;&lt;/a&gt; by Joonas W (&lt;a href="https://www.nuget.org/packages/Joonasw.AspNetCore.SecurityHeaders"&gt;available on NuGet&lt;/a&gt;). It deals with a CSP, HSTS, and HTTP Public Key Pinning (HPKP) headers, but also allows you to cater for inline resources throughout the application using nonces.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to test security headers
&lt;/h2&gt;

&lt;p&gt;When it comes to testing your headers, there are two things to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are they even there at all?&lt;/li&gt;
&lt;li&gt;They are there, but do they work?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Testing for the first question is simple. The simplest thing is to use the developer tools in your browser to view the response headers and see what is present - but you need to know what you're looking for. &lt;/p&gt;

&lt;p&gt;There are also plenty of free tools available online that will scan your application and tell you which headers it has found. Two which I fall back on the most are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.serpworx.com/check-security-headers/"&gt;The Security Header Checker from SerpWorx&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://securityheaders.com/"&gt;SecurityHeaders.com&lt;/a&gt; (by &lt;a href="https://scotthelme.co.uk/"&gt;Scott Helme&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The two are very similar in the way that they work. Once your scan is complete, you get more detail and a summary of the headers that have been checked. SecurityHeaders.com will give you a rating from A+ to F (and R, which I think should stand for ‘Run Away’), whereas SerpWorx gives you a score out of 100.&lt;/p&gt;

&lt;p&gt;Checking that the headers work is a more complex task. It requires you to understand how each of the headers that you implement behaves. Once you understand that, you can create test scenarios to ensure that the headers are working. &lt;/p&gt;

&lt;h2&gt;
  
  
  Example of testing the Content Security Policy (CSP)
&lt;/h2&gt;

&lt;p&gt;Let's consider the following HTML document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Setting CSP Reponse Header&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color:rebeccapurple"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Setting CSP Reponse Header&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Sample page to test the CSP header&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://placehold.it/600x300"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"yup"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;})();&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This document currently has no security headers set. ON page load, it greets the world with a javascript popup, it uses an inline style attribute to add colour to our heading, and it displays an image from an external source.  Once loaded it looks a bit like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l2Tl6yPG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fp794d0n22iswm2my5ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l2Tl6yPG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fp794d0n22iswm2my5ra.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
What we want to do is add a basic CSP to the page to help lock things down. This can be done by adding the following to the document &lt;code&gt;head&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt;  &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;  &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"
  default-src 'self' ;
  "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now when we refresh our page, it looks like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gs8ukS_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/geey3d5dfvz199ian4bo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gs8ukS_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/geey3d5dfvz199ian4bo.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image is broke, the inline style is not working, and the javascript pop-up does not trigger. CHrome's developer tools tell us all about these three issues in the console log. We have three issues, so let's see how they can be addressed.&lt;/p&gt;

&lt;p&gt;The first issue is that our inline style violates our set directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index.html:12 Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'self' ". Either the 'unsafe-inline' keyword, a hash ('sha256-NcqL2O3Vi61pA+um5+nt0/EJDYXH4MJIaeZnKVe0Yro='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we've set this using an attribute on the &lt;code&gt;h1&lt;/code&gt;, we're left with only one option. We have to set &lt;code&gt;unsafe-inline&lt;/code&gt; in the &lt;code&gt;style-src&lt;/code&gt; directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt;  &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;  &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"
  default-src 'self' ;
  style-src 'self' 'unsafe-inline' ;
  "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But why use &lt;code&gt;'unsafe-inline'&lt;/code&gt; rather than a hash or a nonce? The hash and nonce don't work for attributes, they only apply to elements.  You can go ahead and try adding the hash for the inline style, but Chrome is going to ignore you. &lt;/p&gt;

&lt;p&gt;It's worth noting that Gatsby uses a fair bit inline attributes, so those sites are going to need &lt;code&gt;'unsafe-inline'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second issue that the image cannot be loaded as if comes from a different origin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index.html:14 Refused to load the image 'https://placehold.it/600x300' because it violates the following Content Security Policy directive: "default-src 'self' ". Note that 'img-src' was not explicitly set, so 'default-src' is used as a fallback.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To resolve this, we can add &lt;code&gt;https://placehold.it&lt;/code&gt; to the &lt;code&gt;img-src&lt;/code&gt; directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt;  &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;  &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"
  default-src 'self' ;
  style-src 'self' 'unsafe-inline' ;
  img-src 'self' https://placehold.it ;
  "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, our exciting javascript alert is not working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index.html:16 Refused to execute inline script because it violates the following Content Security Policy directive: "default-src 'self' ". Either the 'unsafe-inline' keyword, a hash ('sha256-M0EvshAmM+P/2ftO4FhRfWslEE4wBspM79DQuiCW9SE='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this instance, we using an inline script element, so we can add the hash to the &lt;code&gt;script-src&lt;/code&gt; directive to fix this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt;  &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;  &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"
  default-src 'self' ;
  style-src 'self' 'unsafe-inline' ;
  img-src 'self' https://placehold.it ;
  script-src 'self' 'sha256-M0EvshAmM+P/2ftO4FhRfWslEE4wBspM79DQuiCW9SE=' ;
  "&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may notice that I've specified &lt;code&gt;'self'&lt;/code&gt; on all of the directives. You don't &lt;em&gt;need&lt;/em&gt; to do this, but its purpose is to allow that specific directive from our origin. In most cases, you'll probably trust your origin.&lt;/p&gt;

&lt;p&gt;Once those are all saved, we can reload the page and everything works again. The difference now is that we're telling the user agent what to expect and asking it to ignore everything else. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Security headers perform an important role in asserting the capabilities and requirements of your application to the user agent. How you set them depends upon how your application is created and hosted, but then the result is a set of directives that the user agent should follow. &lt;/p&gt;

&lt;p&gt;Adding the CSP will most definitely break things at first. In reality, it is supposed to. When you move to production, you may well find that you need different values - so you need to test!&lt;/p&gt;

&lt;p&gt;Not only do these contribute to the overall security of the application, but in some cases and also help to improve SEO by contributing to faster page load times.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>security</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Keeping your keys safe in JAMStack</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Fri, 20 Mar 2020 09:42:13 +0000</pubDate>
      <link>https://forem.com/mattnield/keeping-your-keys-safe-in-jamstack-2p74</link>
      <guid>https://forem.com/mattnield/keeping-your-keys-safe-in-jamstack-2p74</guid>
      <description>&lt;p&gt;&lt;strong&gt;Working with Kentico Kontent and Gatsby has been a nice learning curve for me, as I pick up and build upon my front-end developer skillset. You can end up taking quite a lot for granted when you're working with .NET. Securing your calls to an API can be one of these things, as you add things like API keys to your &lt;code&gt;.config&lt;/code&gt; files and make sure that you don't push those files into your git repo.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;When I started on my journey with &lt;a href="https://www.gatsbyjs.com/"&gt;Gatsbyjs&lt;/a&gt; and &lt;a href="https://www.kontent.ai/"&gt;Kentico Kontent&lt;/a&gt;, I wasn't clear on a method that I could use to hide my API keys. 😕 As with most things though, a little digging on Google goes a long way and I managed to find two solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using environment variables&lt;/li&gt;
&lt;li&gt;Create a settings object&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's look at these in a little more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating and using environment variables
&lt;/h3&gt;

&lt;p&gt;Environment variables are settings that are usually stored as key-value pairs that you can use in your application. To store your application settings in environment variables, you can create a &lt;code&gt;.env&lt;/code&gt; file in your project folder.&lt;br&gt;
The &lt;code&gt;.env&lt;/code&gt; file format is just a simple flat file, no hierarchy.  As an example,  my &lt;code&gt;.env&lt;/code&gt; file looks as follows (obviously the values in brackets are replaced):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KONTENT_PROJECT_ID=&amp;lt;Kontent Project ID&amp;gt;
KONTENT_PREVIEW_KEY=&amp;lt;Kontent API Key&amp;gt;
KONTENT_PREVIEW_ENABLED=&amp;lt;true of false&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading that file requires you to have the &lt;a href="https://github.com/motdotla/dotenv"&gt;&lt;code&gt;dotenv&lt;/code&gt;&lt;/a&gt; module in your project. You can install this using the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The using it is as simple as setting it up (in my case at the top of my &lt;code&gt;gatsby.config&lt;/code&gt; file):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require('dotenv').config();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it happens, in my Gatsby project, I have two &lt;code&gt;.env&lt;/code&gt; files, one for running &lt;code&gt;gatsby develop&lt;/code&gt; and one for &lt;code&gt;gatsby build&lt;/code&gt; (one uses the preview mode of Kentico Kontent while the other does not). In order to do this, I pass a little more info to &lt;strong&gt;dotnet&lt;/strong&gt; to tell the configuration which file to look for, bypassing in the node environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`,
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that when I look at my &lt;code&gt;gatsby.config&lt;/code&gt; file, I have a much cleaner file that I can commit to my repo that does not contain my various keys as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  resolve: `@kentico/gatsby-source-kontent`,
  options: {
    deliveryClientConfig: {
      projectId: process.env.KONTENT_PROJECT_ID,
      previewApiKey: process.env.KONTENT_PREVIEW_KEY,
      globalQueryConfig: {
        usePreviewMode: (process.env.KONTENT_PREVIEW_ENABLED == 'true'),
      },
    },
    languageCodenames: [
      `default`
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you may notice is that I'm not simply using the value from the &lt;code&gt;.env&lt;/code&gt; file for the value of &lt;code&gt;usePreviewMode&lt;/code&gt;. There is a good reason for this and very simple reason for this and that is that &lt;code&gt;dotenv&lt;/code&gt; does not support boolean values.  If you want to debug out your environment variables you can use the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(process.env);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which means you'll see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  KONTENT_PREVIEW_ENABLED: 'true',
  KONTENT_PREVIEW_KEY: 'Swiper, no swiping!',
  KONTENT_PROJECT_ID: 'Swiper, no swiping!',
  NODE_ENV: 'development',
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(I actually have a load more in there from my Windows environment variables like &lt;code&gt;PATH&lt;/code&gt;, but we don't need to worry about those here)&lt;/em&gt;&lt;br&gt;
That's it. When you run &lt;code&gt;npm run build&lt;/code&gt; or &lt;code&gt;npm run develop&lt;/code&gt; everything should now be picking up your new settings!&lt;br&gt;
&lt;a href="https://i.giphy.com/media/dIxkmtCuuBQuM9Ux1E/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/dIxkmtCuuBQuM9Ux1E/giphy.gif" alt="It's working!"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Ignore the &lt;code&gt;.env&lt;/code&gt; file!
&lt;/h3&gt;

&lt;p&gt;A key point here is, add your &lt;code&gt;.env&lt;/code&gt; files to the &lt;code&gt;.gitignore&lt;/code&gt; file. The whole point here for me is to not commit your keys and other sensitive data to the git repository. &lt;/p&gt;

&lt;p&gt;To achieve this, just add the following to your &lt;code&gt;.gitignore&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# dotenv environment variable files
.env*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using environment variables with Netlify
&lt;/h3&gt;

&lt;p&gt;I'm my scenario, I'm using &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; to build and host my solution. If you are too, then you may have already come across the environment variables in your projects build &amp;amp; deploy settings:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9VmuyU3M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7odindk7typp9iv0z51q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9VmuyU3M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7odindk7typp9iv0z51q.png" alt="Netlify Environment Variables Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Netlify has no concept of &lt;em&gt;build&lt;/em&gt; or &lt;em&gt;develop&lt;/em&gt; environment variables in my setup (hot I think it can support them), so when we run &lt;code&gt;npm run build&lt;/code&gt;, it simply picks up the available variables and gets on with business.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using environment variables with Azure DevOps
&lt;/h3&gt;

&lt;p&gt;At &lt;a href="https://www.ridgeway.com"&gt;Ridgeway&lt;/a&gt;,  we use &lt;a href="https://azure.microsoft.com/en-us/services/devops"&gt;Azure DevOps&lt;/a&gt; for our build pipelines. Typically, we set up the pipelines using &lt;code&gt;yaml&lt;/code&gt; files, but the screenshot here uses the &lt;em&gt;classic&lt;/em&gt; designer (it's quite an old one):&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kB1sKlIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tz6f4cfehnzp9k8nzlyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kB1sKlIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tz6f4cfehnzp9k8nzlyu.png" alt="DevOps  Environment Variables Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're editing a &lt;code&gt;yaml&lt;/code&gt; pipeline, then the option is still there if you click &lt;strong&gt;Variables&lt;/strong&gt;  in the top right while editing the pipeline.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hgG_zRpn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n5e1i69o4cgx9iprlpbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hgG_zRpn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n5e1i69o4cgx9iprlpbw.png" alt="How to edit variables in Azure DevOps"&gt;&lt;/a&gt;&lt;br&gt;
Then you can just set the values you want. The options here to make things secret are quite a nice touch, as are the tips on how to use them.&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---n681UME--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jwvs7cocheq203uoa2pq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---n681UME--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jwvs7cocheq203uoa2pq.png" alt="Setting up variables in DevOps with yaml"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Settings object
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Creating and using a settings object
&lt;/h3&gt;

&lt;p&gt;Another option I've seen in use is the creation of a settings object in a separate file. So for example, on one project we have a file called &lt;code&gt;gatsby.keys&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  enablePreviewMode:  false,
  enableSecuredMode:  true,
  securedApiKey:  'Swiper, no swiping!',
  previewApiKey:  'Swiper, no swiping!'
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is then used in the &lt;code&gt;gatsby.config&lt;/code&gt; file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const  keys = require('./gatsby-keys');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variables are then used to set up the plugins as before.&lt;/p&gt;

&lt;p&gt;This method supports boolean values, so we don't need to do any additional work with those. Again, this file needs to be excluded from the repository using the &lt;code&gt;.gitignore&lt;/code&gt; file to make sure that we don't push the keys into the wrong place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Settings objects in build pipelines
&lt;/h3&gt;

&lt;p&gt;I've only tried this with Azure DevOps, and it required me to add a custom pipeline component to create the key's file. So I have a step in my &lt;code&gt;yaml&lt;/code&gt; that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: eliostruyf.build-task.custom-build-task.file-creator@5
  displayName: 'Create settings keys'
  inputs:
    fileoverwrite: true
    filepath: 'gatsby-keys.js'
    filecontent: |
      module.exports = {
        enablePreviewMode: true,
        enableSecuredMode: false,
        securedApiKey: 'Swiper, no swiping!',
        previewApiKey: 'Swiper, no swiping!'
      };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can probably spot the flaw in this implementation, right? I'm not using variables so actually, this is a massive fail as those keys are directly in my &lt;code&gt;yaml&lt;/code&gt; file and so also in source control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3owypkSIpM8xw6p7W0/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3owypkSIpM8xw6p7W0/giphy.gif" alt="Fail!"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(on the upside, it's a private repo)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;These are to the two methods that I came across while working on both work and personal projects. The first exposure I had was the settings object. While it solves the issue of booleans, it's note really my favourite. The environment variables appears to be a much more robust approach to things and it's the one I'm going to be using (and asking my team to use) going forward.&lt;/p&gt;

&lt;p&gt;If you can find the time, I recommend testing both out and seeing which works best in your case.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@chunlea?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Chunlea Ju&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/keys?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gatsby</category>
      <category>jamstack</category>
      <category>kenticokontent</category>
    </item>
    <item>
      <title>Testing Macros in Kentico</title>
      <dc:creator>Matt Nield</dc:creator>
      <pubDate>Wed, 26 Feb 2020 15:20:15 +0000</pubDate>
      <link>https://forem.com/mattnield/testing-macros-in-kentico-ide</link>
      <guid>https://forem.com/mattnield/testing-macros-in-kentico-ide</guid>
      <description>&lt;p&gt;&lt;strong&gt;Macros are a very powerful part of Kentico and can be essential when it comes to extending admin areas of Kentico and adding your own custom modules and UI elements. This simple - sometimes overlooked tip - will help you along your way.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kentico provides the developer with a powerful tool in the shape of macros. Most developers who have either developed with the Kentico portal engine or extended the admin area will have come across them. Surprisingly, most people I speak to are reliant on the event log when they need to figure out why their page or permissions are not working.  What can be much more helpful is to use the Macro Console&lt;/p&gt;

&lt;h2&gt;
  
  
  How to open and use the macro console
&lt;/h2&gt;

&lt;p&gt;To open the macro console in Kentico, you navigate to System &amp;gt; Macros &amp;gt; Console  (see below). The console itself is fairly straightforward. Once opened, you see the following four elements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A text area for entering your expressions&lt;/li&gt;
&lt;li&gt;An option of the evaluation mode to be used&lt;/li&gt;
&lt;li&gt;A results tree&lt;/li&gt;
&lt;li&gt;An output text area&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EM-q2ATn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nzqirfqkxc74xhq4udph.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EM-q2ATn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nzqirfqkxc74xhq4udph.gif" alt="Opening the Macro Console in Kentico 12"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Expression
&lt;/h3&gt;

&lt;p&gt;This is a simple as it sounds; a text area for entering a macro expression that you want to evaluate. It benefits from auto-complete to make your life easier and will take account of any custom macro methods or module classes that you have registered in your solution.&lt;/p&gt;

&lt;p&gt;As an example, entering the expression &lt;code&gt;SiteObjects.Documents.TopN(5)&lt;/code&gt; will return a list of the top 5 documents on the site (ordered by &lt;code&gt;NodeID&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You’re able to do quite a lot in here, from simply listing our objects or properties to applying transformations. So something like &lt;code&gt;...TopN(5).ApplyTransformation("Ridgeway.Product.Card")&lt;/code&gt; would result in the generated markup from the supplied transformation being displayed in the Output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluation modes
&lt;/h3&gt;

&lt;p&gt;The three evaluation modes that you have available are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Virtual Data&lt;/li&gt;
&lt;li&gt;Real data&lt;/li&gt;
&lt;li&gt;Real data with displayed values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These options affect how the information in the macro tree are presented back to you. I personally find the Real data with displayed values to be the most useful mode, as you get to see the display names in the tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;The results are a macro tree representing the returned result of the resolved expression. Clicking on an item in the results tree will update the expression. The next time you click Execute, your updated expression is the one which will be run.&lt;/p&gt;

&lt;p&gt;In our example above, we get and &lt;code&gt;InfoObjectCollection&lt;/code&gt;, which contains 5 elements. If you’re using Real data with displayed values, then you should see something like this in the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nMChQxEW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cyeta35boxp983b9hp6v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nMChQxEW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cyeta35boxp983b9hp6v.png" alt="Macro tree result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Output
&lt;/h3&gt;

&lt;p&gt;This is the text output of the resolved expressions. I’ve found this to be of most use when quickly testing transformations in modules, simple text transformations, and checking UI element permissions.&lt;/p&gt;

&lt;p&gt;Again, with the above example you’ll see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CC1LFuAk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/av9gd8agy5vdajyyvv7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CC1LFuAk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/av9gd8agy5vdajyyvv7f.png" alt="Macro expression output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example - UI Elements
&lt;/h2&gt;

&lt;p&gt;A recent project I’ve been working featured a lot of extensions to Kentico with a single, large module that encapsulated areas of the businesses order fulfilment. This meant a lot of new classes and a lot of checking permissions before accessing data. Permissions and a UI access are of course all delivered out-of-the-box with Kentico, but we needed more. An example of this was that we had physical stores that would accept click-and-collect orders. Members of the store team needed to be able to log into a collection management application that we created in Kentico to view and manage the orders for their store. Here, permissions and UI controls can only do so much, we either need to start creating some custom pages and controls, order use Kentico's UI tools to filter the data that individuals can see.&lt;/p&gt;

&lt;p&gt;The model we built was to create a binding table between our Store class and Kentico’s User class as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oiPovXCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fefkreuxg9poref02wv0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oiPovXCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fefkreuxg9poref02wv0.jpg" alt="Store user binding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This binding table was then used to show a list of all of the assigned users for a given store (or vice versa) so that the admin team could set up the users correctly. All of that was pretty straightforward, but limiting the data for a given user was where we needed to start using macros.&lt;/p&gt;

&lt;p&gt;The first macro method in use was simply called &lt;code&gt;GetUserStores&lt;/code&gt;. As its name suggests, this method returns a list of the stores which the user is already assigned to. There is also naturally a counterpart that will return the users assigned to a given store.&lt;/p&gt;

&lt;p&gt;For the UI element, we just used a simple UI grid as described in the Creating Custom Modules example in the Kentico documentation; the macro method was going to be used to filter the data that the UI grid would display. This was achieved by setting the where condition of the listing to the following macro expression:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This says that anyone with the &lt;code&gt;ViewAllStores&lt;/code&gt; permission or who has an admin privilege or above can see everything, otherwise, we limit the list of results to those that the current user is assigned.&lt;/p&gt;

&lt;p&gt;By now you’re probably wondering when I’m going to get to the bit about testing macros rather than how we built the UI. The above expression was originally written using the Macro Console. The key part of the expression above is &lt;code&gt;CurrentUser.GetUserStores().Table.Rows.Transform("{%StoreID%"+"},") %}&lt;/code&gt;. This is a fairly simple expression, but to make sure we get it right, we created it in the macro console before testing in the UI grid.  One thing that always catches me out when using &lt;code&gt;Transform()&lt;/code&gt; is that I can't terminate the expression using &lt;code&gt;%}&lt;/code&gt;. Doing this prematurely terminates the entire macro expression, so you need to break it apart by concatenating the string.  Finding this out in the Macro Console is much easier than wondering why your page isn't quite loading as you'd expected or why the UI page that you just made isn't displaying the data that you'd expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The Macro Console is a great and underused part of the Kentico platform. It allows a developer to quickly test out the expressions that they need without needing to make more fundamental changes to transformations or UI elements. It’s also very useful in production sites for quickly checking the information in a safe manner (i.e. not digging about in SQL server). Now that we're preparing to move on to Kentico 12 and aiming towards MVC for future solutions at Ridgeway, I still know that this is going to continue to play a role for us as we continue to build on top of Kentico admin UI to meet our client’s needs.&lt;/p&gt;

</description>
      <category>kentico</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
