<?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>DEV Community: André König</title>
    <description>The latest articles on DEV Community by André König (@andre).</description>
    <link>https://dev.to/andre</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%2F27227%2Fac81c14f-8b8d-4c6c-98c9-2727d149c50f.jpeg</url>
      <title>DEV Community: André König</title>
      <link>https://dev.to/andre</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andre"/>
    <language>en</language>
    <item>
      <title>How to Avoid Network Policies Interfering with Workload Identity on the Google Kubernetes Engine</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Tue, 16 Aug 2022 12:00:00 +0000</pubDate>
      <link>https://dev.to/andre/how-to-avoid-network-policies-interfering-with-workload-identity-on-the-google-kubernetes-engine-2of</link>
      <guid>https://dev.to/andre/how-to-avoid-network-policies-interfering-with-workload-identity-on-the-google-kubernetes-engine-2of</guid>
      <description>&lt;p&gt;Today we stumbled upon an interesting case which I want to share as it might help you in your debugging journey.&lt;/p&gt;

&lt;p&gt;Let's assume you have the following infrastructure setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes Cluster on the Google Kubernetes Engine&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/kubernetes-engine/docs/concepts/workload-identity"&gt;Workload Identity&lt;/a&gt; enabled.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;egress&lt;/code&gt; &lt;a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/"&gt;Network Policies&lt;/a&gt; in use.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;You might think everything is fine, but your service which is communicating with Google APIs (like Google Cloud Storage Client Libraries, etc.) complains with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Could not load the default credentials.
Browse to https://cloud.google.com/docs/authentication/getting-started &lt;span class="k"&gt;for &lt;/span&gt;more information.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first reaction is: How can this be the case when I configured Workload Identity as recommended? When looking behind the curtain it is likely that the culprit here is not Workload Identity at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cause
&lt;/h2&gt;

&lt;p&gt;In our case, the root cause was a restrictive network policy which blocked the &lt;code&gt;egress&lt;/code&gt; traffic to the &lt;a href="https://cloud.google.com/kubernetes-engine/docs/concepts/workload-identity#metadata_server"&gt;GKE metadata server&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;The solution depends slightly on the Kubernetes version you're operating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.21.0-gke.1000 and later&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-network-policy&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;egress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;988&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;ipBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;cidr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;169.254.169.252/32&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Egress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prior versions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-network-policy&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;egress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;988&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;ipBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;cidr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;127.0.0.1/32&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Egress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>googlecloud</category>
      <category>security</category>
    </item>
    <item>
      <title>Deactivate the Scrollbar. The sidebar is visible!</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Tue, 12 Jan 2021 15:11:00 +0000</pubDate>
      <link>https://dev.to/andre/deactivate-the-scrollbar-the-sidebar-is-visible-5ekl</link>
      <guid>https://dev.to/andre/deactivate-the-scrollbar-the-sidebar-is-visible-5ekl</guid>
      <description>&lt;p&gt;Imagine the following – pretty common – scenario:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lJy30Oz2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ft948weh8juo3pq03gbf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lJy30Oz2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ft948weh8juo3pq03gbf.png" alt="Sidebar Menu Layout" width="880" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have some kind of UI where you open up a sidebar by clicking on a Hamburger icon. The sidebar is positioned above the actual UI components. So far, nothing special 🎉 The case hits you when you have a lot of components within the actual view so that the browser does what it is really good in, &lt;strong&gt;scrolling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So the question is, how to &lt;strong&gt;temporarily deactivate scrolling when the sidebar has been opened&lt;/strong&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  A 🍔, please.
&lt;/h2&gt;

&lt;p&gt;Before diving into the solution space, let's set the foundation and define the actual &lt;code&gt;Hamburger&lt;/code&gt; component. This component is responsible for handling the sidebar visibility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Hamburger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;isSidebarVisible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsSidebarVisible&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;onClick&lt;/span&gt; &lt;span class="o"&gt;=&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;setIsSidebarVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isMenuOpen&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;🍔&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;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;This is only the component for the visibility state handling of the sidebar – the Hamburger icon. The actual sidebar gets displayed via &lt;a href="https://reactjs.org/docs/portals.html"&gt;React Portals&lt;/a&gt;. I have omitted the usage of Portals here for reasons of simplicity.&lt;/p&gt;

&lt;p&gt;Now, where we have the actual state in place, we can utilize that information for toggling whether the viewport scrolling should be active or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meet the &lt;code&gt;&amp;lt;Scrollbar /&amp;gt;&lt;/code&gt; component
&lt;/h3&gt;

&lt;p&gt;One of my favorite aspects about &lt;code&gt;styled-components&lt;/code&gt; is the paradigm of using encapsulated components for creating visual representations. But you don't need to stop there, you can utilize it for controlling global behavior as well. The following snippet shows you how to define a component which controls the global scrollbar by using styled-component's own &lt;code&gt;createGlobalStyle&lt;/code&gt; mechanism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;deactivated&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Scrollbar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createGlobalStyle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`
  body {
    overflow: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deactivated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&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="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With this component in place, we can now deactivate the global scrollbar via &lt;code&gt;&amp;lt;Scrollbar deactivated /&amp;gt;&lt;/code&gt; and activate it by rendering just &lt;code&gt;&amp;lt;Scrollbar /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the &lt;code&gt;&amp;lt;Scrollbar /&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Back to our &lt;code&gt;&amp;lt;Hamburger /&amp;gt;&lt;/code&gt; component. Integrating the scrollbar component is quite easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&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;Hamburger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;isSidebarVisible&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsSidebarVisible&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;onClick&lt;/span&gt; &lt;span class="o"&gt;=&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;setIsSidebarVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isSidebarVisible&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;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Scrollbar&lt;/span&gt; &lt;span class="na"&gt;deactivated&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isSidebarVisible&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;🍔&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;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;Now whenever the sidebar has been opened, this state indicates that the scrollbar should be deactivated and vice versa 🥳&lt;/p&gt;

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

&lt;p&gt;Although the solution demonstrates quite a nice declarative solution, please take it with a grain of salt. Encapsulating global behavior should be used sparsely. When using such an encapsulation in different places of your code base, this certain areas gets hard to maintain over time as you might loose track of them. Even with this word of caution, there are cases, like the described scenario, where it might be quite handy to wrap global behavior in a component and use it conditionally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;A full example can be found here: &lt;a href="https://stackblitz.com/edit/conditional-scrollbar?file=index.tsx"&gt;conditional-scrollbar&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>styledcomponents</category>
    </item>
    <item>
      <title>First Impressions of Knative Eventing</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Wed, 10 Jul 2019 10:26:23 +0000</pubDate>
      <link>https://dev.to/andre/first-impressions-of-knative-eventing-bn5</link>
      <guid>https://dev.to/andre/first-impressions-of-knative-eventing-bn5</guid>
      <description>&lt;p&gt;You might have heard of &lt;a href="https://knative.dev/" rel="noopener noreferrer"&gt;Knative&lt;/a&gt; – the serverless application development platform on top of Kubernetes. A lot of buzzwords, I know, but in essence it provides multiple APIs for deploying your applications without thinking (too much) about Kubernetes machinery.&lt;/p&gt;

&lt;p&gt;At the moment, Knative can be differentiated into three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://knative.dev/docs/serving/" rel="noopener noreferrer"&gt;Knative Serving&lt;/a&gt; - Deploying HTTP-based applications – think of AWS Lambda or Google Cloud Functions &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://knative.dev/docs/build/" rel="noopener noreferrer"&gt;Knative Build&lt;/a&gt; - Helps you to avoid touching containers at all. You provide code and the rest will happen automagically.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://knative.dev/docs/eventing/" rel="noopener noreferrer"&gt;Knative Eventing&lt;/a&gt; - Helps you to build event-driven applications 💥&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might know that I'm a huge fan of event-driven architectures. This is why we will explore &lt;em&gt;Knative Eventing&lt;/em&gt; in this post a little bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do I need?
&lt;/h2&gt;

&lt;p&gt;Due to the nature of &lt;em&gt;Knative&lt;/em&gt; as a serverless platform on top of Kubernetes, you need – 🎉 – a Kubernetes cluster with an installed Service Mesh, like &lt;a href="https://istio.io/" rel="noopener noreferrer"&gt;Istio&lt;/a&gt;. No worries, if you don't know what this Istio-thingy is all about. Please ignore it for the moment and just treat it as a requirement.&lt;/p&gt;

&lt;p&gt;For everyone who is not a proud owner of a Kubernetes cluster yet, I recommend creating one on the &lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Platform (GCP)&lt;/a&gt;. In general the following steps are required:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a cluster on GCP with the Istio addon&lt;/li&gt;
&lt;li&gt;Install Knative&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To keep things DRY and not duplicating content, you can find a good description in the official docs of &lt;em&gt;Knative&lt;/em&gt;: &lt;a href="https://knative.dev/docs/install/knative-with-gke/" rel="noopener noreferrer"&gt;Install on Google Kubernetes Engine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;⚠️ Don't be quenched by the node autoscaling configuration (1 - 10 nodes). For this demo, you can just remove &lt;code&gt;--enable-autoscaling --min-nodes=1 --max-nodes=10&lt;/code&gt; and replace it with &lt;code&gt;--num-nodes 1&lt;/code&gt;. This results in a single node cluster which is sufficient for our little exploration here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our goal
&lt;/h2&gt;

&lt;p&gt;So what is our goal here? I thought of a simple scenario which demonstrates all the essential key pieces without to much ceremony involved. The result is the following simple use case:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Establishing an emitter which sends a JSON-formatted event every minute and having an application which spins up automatically and just displays the respective event.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuw4n1y7x6edwze7566mv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuw4n1y7x6edwze7566mv.png" width="661" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let the events flow ...
&lt;/h2&gt;

&lt;p&gt;The described use case above can be translated into the following architecture which demonstrates how the flow of events can be achieved with &lt;em&gt;Knative Eventing&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nm0xey5uxm4sumia4ec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nm0xey5uxm4sumia4ec.png" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although that might look complex, the introduced indirection with the &lt;code&gt;Broker&lt;/code&gt; and &lt;code&gt;Trigger&lt;/code&gt; makes a lot of sense in the end. Let us analyze it piece by piece. &lt;/p&gt;

&lt;h3&gt;
  
  
  Broker
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Broker&lt;/code&gt; acts as a central eventing gateway. It receives events from sources and delegates it to the respective subscribers who are interested in the event.&lt;/p&gt;

&lt;p&gt;In our scenario, we will create broker in the &lt;code&gt;default&lt;/code&gt; namespace by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl label namespace default knative-eventing-injection&lt;span class="o"&gt;=&lt;/span&gt;enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the creation of the broker via:&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="nv"&gt;$ &lt;/span&gt;kubectl get broker
NAME      READY   REASON   HOSTNAME                                   AGE
default   True             default-broker.default.svc.cluster.local   22s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Event Source
&lt;/h3&gt;

&lt;p&gt;Acts as an origin of events. Imagine a microservice kind of architecture. In such a scenario you would have multiple of such event sources. Each of them will emit domain specific events.&lt;/p&gt;

&lt;p&gt;There are several possibilities to establish an actual event source. Beside coding own sources, &lt;em&gt;Knative Eventing&lt;/em&gt; ships with a bunch of predefined of those. To name a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: Repository / Organization events, like: PR created, commits pushed, etc.&lt;/li&gt;
&lt;li&gt;Apache Kafka: Stream Kafka messages to &lt;em&gt;Knative&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes: Brings Kubernetes cluster events to &lt;em&gt;Knative&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find a complete list of existing sources in the &lt;a href="https://knative.dev/docs/eventing/sources/index.html" rel="noopener noreferrer"&gt;Knative docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another interesting predefined component is the &lt;code&gt;Cron Job&lt;/code&gt; source. It allows to emit messages in a timely manner. This is exactly the one, we want to use in our demo here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# filename: source.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sources.eventing.knative.dev/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CronJobSource&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;event-emitter&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{"message":&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Hello&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;world!"}'&lt;/span&gt;
  &lt;span class="na"&gt;sink&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eventing.knative.dev/v1alpha1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broker&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is everything you need to define a &lt;code&gt;Cron Job&lt;/code&gt; source. You can apply it via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; source.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterwards, the &lt;code&gt;event-emitter&lt;/code&gt; will ...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;... send the event defined in &lt;code&gt;data&lt;/code&gt; every minute&lt;/li&gt;
&lt;li&gt;... send this message to the &lt;code&gt;default broker&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;p&gt;The service is your actual application. The one which is responsible for receiving the respective event and performing some business logic. In our example, we just use an existing container image which takes a received event and prints it on &lt;code&gt;stdout&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The definition looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# service.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serving.knative.dev/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dumper&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gcr.io/knative-releases/github.com/knative/eventing-sources/cmd/event_display&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service will be alive after executing &lt;code&gt;kubectl apply -f service.yaml&lt;/code&gt; and the logs can be digested via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="nt"&gt;-f&lt;/span&gt;  &lt;span class="nt"&gt;-l&lt;/span&gt; serving.knative.dev/service&lt;span class="o"&gt;=&lt;/span&gt;dumper &lt;span class="nt"&gt;-c&lt;/span&gt; user-container &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although we have applied &lt;code&gt;Broker&lt;/code&gt;, &lt;code&gt;Source&lt;/code&gt; and the &lt;code&gt;Service&lt;/code&gt; you might be wondering why you can't see any output yet. This leads us to our last missing puzzle piece, the &lt;code&gt;Trigger&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;Trigger&lt;/code&gt; is an interesting beast to be honest. It acts as an indirection layer in which you can define &lt;em&gt;which events should be send to which service&lt;/em&gt;. It basically binds a respective event type to a specific service. Nice and declarative, eh?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# trigger.yaml&lt;/span&gt;

&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eventing.knative.dev/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Trigger&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trigger&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;subscriber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serving.knative.dev/v1alpha1&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dumper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So after a &lt;code&gt;kubectl apply -f trigger.yaml&lt;/code&gt;, we basically created a component which &lt;em&gt;triggers&lt;/em&gt; the service every time a new event arrives. You should see an output in the logs of the service from now on.&lt;/p&gt;

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

&lt;p&gt;In some of my previous customer projects we created such an eventing infrastructure ourselves. You may already have had the experience to build such a thingy. It is quite a lot of work, right? Establishing the broker infrastructure (via &lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt;, &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Apache Kafka&lt;/a&gt;, etc.) and defining all the event routing manually just to name two aspects of the overall work. &lt;em&gt;Knative Eventing&lt;/em&gt; ships with the correct primitives IMHO. It enables you to perform all the work you had to do manually in the past in a nice, declarative way.&lt;/p&gt;

&lt;p&gt;My assumption is that &lt;em&gt;Knative&lt;/em&gt; in general is facing a bright future. A lot of engineers just avoided touching Kubernetes due to its high learning curve. You might consider the ecosystem again. &lt;em&gt;Knative&lt;/em&gt; is here to let you focus on shipping code without a lot of infrastructural overhead.&lt;/p&gt;

&lt;p&gt;What is your impression of &lt;em&gt;Knative&lt;/em&gt; and &lt;em&gt;Knative Eventing&lt;/em&gt; in general?&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>knative</category>
      <category>eventing</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Handling errors in GraphQL</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Wed, 14 Feb 2018 09:26:09 +0000</pubDate>
      <link>https://dev.to/andre/handling-errors-in-graphql--2ea3</link>
      <guid>https://dev.to/andre/handling-errors-in-graphql--2ea3</guid>
      <description>

&lt;p&gt;There has been some &lt;a href="https://github.com/graphcool/prisma/issues/1738"&gt;discussions&lt;/a&gt; recently about how to handle errors in GraphQL resolvers. I mentioned &lt;a href="https://github.com/thebigredgeek/apollo-errors"&gt;apollo-errors&lt;/a&gt; because I had very good experiences with it. In this article, I want to take the chance and describe my approach of handling errors in a GraphQL API.  &lt;/p&gt;

&lt;h2&gt;Anatomy of an error&lt;/h2&gt;

&lt;p&gt;Before diving deep into how to establish a proper error handling, I would like to differentiate a little bit what kind of errors we are talking about here. Basically, as in all user-facing systems, there are two possible error types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Controlled errors&lt;/code&gt;: An exception which indicates that the user did something wrong (e.g. Wrong login credentials, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Uncontrolled errors&lt;/code&gt;: The counterpart. An exception that indicates that something really bad happened (e.g. storage system not available, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ones we are most interested in are the &lt;code&gt;controlled errors&lt;/code&gt;. These are the ones which you as the software engineer define and throw when the particular case has happened. &lt;code&gt;Uncontrolled errors&lt;/code&gt;, as the name states, are the ones which can happen all the time. Even if they are not &lt;em&gt;controllable&lt;/em&gt;, you will learn how to handle them gracefully as well.  &lt;/p&gt;

&lt;h2&gt;The common approach&lt;/h2&gt;

&lt;p&gt;When reading about GraphQL, you will often see the following example:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;areCredentialsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Authentication required"&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 is a simple approach and might be sufficient in most cases. The downside here is that a respective client has a hard time figuring what kind of an error this actually is. A &lt;code&gt;err.message === "Authentication required"&lt;/code&gt; in the client is not cool at all.&lt;/p&gt;

&lt;p&gt;It would be great to have a kind of error type, right? This is where &lt;a href="https://github.com/thebigredgeek/apollo-errors"&gt;apollo-errors&lt;/a&gt; comes to play. Let's go!&lt;/p&gt;

&lt;h2&gt;A more robust approach&lt;/h2&gt;

&lt;p&gt;Let's consider the following scenario: We have a login mutation and we want to throw an error when the user entered wrong credentials. A possible type could be &lt;code&gt;WrongCredentialsError&lt;/code&gt;. The first step to do is creating the actual error type:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// path: resolvers/mutation/login/errors/WrongCredentialsError.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"apollo-errors"&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;WrongCredentialsError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"WrongCredentialsError"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"The provided credentials are invalid."&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WrongCredentialsError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now where we have our error type, we can throw it from our &lt;code&gt;login&lt;/code&gt; mutation resolver:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// path: resolvers/mutation/login/index.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WrongCredentialsError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"./errors/WrongCredentialsError"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LoginInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LoginInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&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;areCredentialsValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;checkCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;areCredentialsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WrongCredentialsError&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;So when this mutation gets executed and the user entered wrong credentials the GraphQL API would respond with:&lt;/p&gt;



&lt;div class="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="s2"&gt;"data"&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="s2"&gt;"errors"&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="s2"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"The provided credentials are invalid."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"WrongCredentialsError"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"time_thrown"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2018-02-14T00:40:50.954Z"&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="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pretty, isn't it? So, in theory the GraphQL API would respond with this. There is one missing puzzle piece. Due to the different error structure, we have to tell the GraphQL API endpoint that those errors should be formatted differently.&lt;/p&gt;

&lt;p&gt;But no worries, installing the formatter is an one-time shot and easily done. The following describes how to hook the formatter up on a &lt;a href="https://github.com/graphcool/graphql-yoga"&gt;graphql-yoga&lt;/a&gt; based application.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GraphQLServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"graphql-yoga"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formatError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"apollo-errors"&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;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;formatError&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;GraphQLServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GraphQL API is running on localhost:4000'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's it! You're able to throw named &lt;code&gt;controlled errors&lt;/code&gt; now.&lt;/p&gt;

&lt;h2&gt;Handling uncontrolled errors gracefully&lt;/h2&gt;

&lt;p&gt;As promised above, I mentioned to give you an approach to handle &lt;code&gt;uncontrolled errors&lt;/code&gt; gracefully as well. You may have read from the code snippets, that I use &lt;a href="https://www.prismagraphql.com/"&gt;Prisma&lt;/a&gt; for interacting with my database. Let us assume that I've messed something up (e.g. sent a stuffy query to my database, etc.). In those cases, where something really bad happened, we want to inform the client that a &lt;code&gt;FatalError&lt;/code&gt; occurred. How can we achieve this?&lt;/p&gt;

&lt;p&gt;One approach would be to put each Prisma interaction in a &lt;code&gt;try / catch&lt;/code&gt; and throw the &lt;code&gt;FatalError&lt;/code&gt; there. That would work, but is pretty cumbersome because you have to handle that in all your resolvers.&lt;/p&gt;

&lt;p&gt;The other approach could be to wrap all our resolvers into a wrapper that executes the actual resolver and checks if that resolver didn't throw an &lt;code&gt;uncontrolled error&lt;/code&gt;. Let us call this wrapper &lt;code&gt;helmet&lt;/code&gt;. It could look like:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// path: resolvers/helmet.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FatalError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"./errors/FatalError"&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;helmet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;args&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// Try to execute the actual resolver and return&lt;/span&gt;
    &lt;span class="c1"&gt;// the result immediately.&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// Due to the fact that we are using Prisma, we can assume&lt;/span&gt;
    &lt;span class="c1"&gt;// that each error from this layer has a `path` attribute.&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// Note: The `FatalError` has been created before by&lt;/span&gt;
    &lt;span class="c1"&gt;// using `apollo-errors` `createError` function.&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FatalError&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;helmet&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to actually handle the &lt;code&gt;uncontrolled errors&lt;/code&gt; gracefully, you have to wrap your resolvers into that &lt;code&gt;helmet&lt;/code&gt; function. Here for example, we use the &lt;code&gt;login&lt;/code&gt; mutation described above:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// path: resolvers/mutation/index.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;helmet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"../helmet"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"./login"&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;Mutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;helmet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Mutation&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;p&gt;Even when just throwing an &lt;code&gt;Error&lt;/code&gt; object right away might be sane in some scenarios, I would suggest considering an approach like the one described in this post for larger applications. Remember, one of GraphQL's strengths is its expressiveness. Why shouldn't you treat your errors also like that?&lt;/p&gt;

&lt;p&gt;I hope you enjoyed the post and I'm happy to hear your thoughts :)&lt;/p&gt;


</description>
      <category>graphql</category>
      <category>prisma</category>
      <category>errors</category>
    </item>
    <item>
      <title>Deploying a Prisma cluster to Kubernetes</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Tue, 13 Feb 2018 06:52:10 +0000</pubDate>
      <link>https://dev.to/andre/deploying-a-prisma-cluster-to-kubernetes--3lbi</link>
      <guid>https://dev.to/andre/deploying-a-prisma-cluster-to-kubernetes--3lbi</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally written as a tutorial for the &lt;a href="https://www.prismagraphql.com/docs/tutorials/cluster-deployment/kubernetes-aiqu8ahgha"&gt;official Prisma documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you will learn how to deploy a &lt;a href="http://prismagraphql.com/"&gt;Prisma&lt;/a&gt; server on &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Prisma is thin layer around your database which exposes a GraphQL API for interacting with your data. It helps you to build your business logic on top by defining an own GraphQL API which communicates with this particular Prisma service.&lt;/p&gt;

&lt;p&gt;Kubernetes is a container orchestrator that helps with deploying and scaling of your containerized applications.&lt;/p&gt;

&lt;p&gt;The setup in this tutorial assumes that you have a running Kubernetes cluster in place. There are several providers out there that gives you the possibility to establish and maintain a production grade cluster. This tutorial aims to be provider agnostic, because Kubernetes is actually the abstraction layer. The only part which differs slightly is the mechanism for creating &lt;code&gt;persistent volumes&lt;/code&gt;. For demonstration purposes, we use the &lt;a href="https://cloud.google.com/kubernetes-engine"&gt;Kubernetes Engine&lt;/a&gt; on the &lt;a href="https://cloud.google.com/"&gt;Google Cloud Platform&lt;/a&gt; in this tutorial.&lt;/p&gt;

&lt;p&gt;I compiled all the files for you in this &lt;a href="https://github.com/akoenig/prisma-kubernetes-deployment"&gt;repository&lt;/a&gt; so that you don't have to copy and paste out of this blog post :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;If you haven't done that before, you need to fulfill the following prerequisites before you can deploy a Prisma cluster on Kubernetes. You need ...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;... a running Kubernetes cluster (e.g. on the Google Cloud Platform)&lt;/li&gt;
&lt;li&gt;... a local version of &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/"&gt;kubectl&lt;/a&gt; which is configured to communicate with your running Kubernetes cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can go ahead now and create a new directory on your local machine – call it &lt;code&gt;kubernetes-demo&lt;/code&gt;. This will be the reference directory for our journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a separate namespace
&lt;/h2&gt;

&lt;p&gt;As you may know, Kubernetes comes with a primitive called &lt;code&gt;namespace&lt;/code&gt;. This allows you to group your applications logically. Before applying the actual namespace on the cluster, we have to write the definition file for it. Inside our project directory, create a file called &lt;code&gt;namespace.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Namespace
metadata:
  name: prisma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This definition will lead to a new namespace, called &lt;code&gt;prisma&lt;/code&gt;. Now, with the help of &lt;code&gt;kubectl&lt;/code&gt;, you can apply the namespace by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; namespace.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterwards, you can perform a &lt;code&gt;kubectl get namespaces&lt;/code&gt; in order to check if the actual namespace has been created. You should see the following on a fresh Kubernetes cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ kubectl get namespaces
NAME            STATUS    AGE
default         Active    1d
kube-public     Active    1d
kube-system     Active    1d
prisma          Active    2s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MySQL
&lt;/h2&gt;

&lt;p&gt;Now that we have a valid namespace in which we can rage, it is time to deploy MySQL. Kubernetes separates between stateless and stateful deployments. A database is by nature a stateful deployment and needs a disk to actually store the data. As described in the introduction above, every cloud provider comes with a different mechanism of creating disks. In the case of the &lt;a href="https://cloud.google.com"&gt;Google Cloud Platform&lt;/a&gt;, you can create a disk by following the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;a href="https://console.cloud.google.com"&gt;Google Cloud Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;a href="https://console.cloud.google.com/compute/disks"&gt;Disk section&lt;/a&gt; and select &lt;code&gt;Create&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please fill out the form with the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; Should be &lt;code&gt;db-persistence&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zone:&lt;/strong&gt; The zone in which the Nodes of your Kubernetes cluster are deployed, e.g. &lt;code&gt;europe-west-1c&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk type:&lt;/strong&gt; For a production scenario &lt;code&gt;SSD persistent disk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source type:&lt;/strong&gt; &lt;code&gt;None (blank disk)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Size (GB):&lt;/strong&gt; Select a size that fits your requirements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption:&lt;/strong&gt; &lt;code&gt;Automatic (recommended)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Select &lt;code&gt;Create&lt;/code&gt; for actually creating the disk.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; To keep things simple, we created the disk above manually. You can automate that process by provisioning a disk via &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt; as well, but this is out of the scope of this tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the MySQL Pod
&lt;/h3&gt;

&lt;p&gt;Now where we have our disk for the database, it is time to create the actual deployment definition of our MySQL instance. A short reminder: Kubernetes comes with the primitives of &lt;code&gt;Pods&lt;/code&gt; and &lt;code&gt;ReplicationControllers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;Pod&lt;/code&gt; is like a "virtual machine" in which a containerized application runs. It gets an own internal IP address and (if configured) disks attached to it. The &lt;code&gt;ReplicationController&lt;/code&gt; is responsible for scheduling your &lt;code&gt;Pod&lt;/code&gt; on cluster nodes and ensuring that they are running and scaled as configured.&lt;/p&gt;

&lt;p&gt;In older releases of Kubernetes it was necessary to configure those separately. In recent versions, there is a new definition resource, called &lt;code&gt;Deployment&lt;/code&gt;. In such a configuration you define what kind of container image you want to use, how much replicas should be run and, in our case, which disk should be mounted.&lt;/p&gt;

&lt;p&gt;The deployment definition of our MySQL database looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: database
  namespace: prisma
  labels:
    stage: production
    name: database
    app: mysql
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        stage: production
        name: database
        app: mysql
    spec:
      containers:
        - name: mysql
          image: 'mysql:5.7'
          args:
            - --ignore-db-dir=lost+found
            - --max-connections=1000
            - --sql-mode=ALLOW_INVALID_DATES,ANSI_QUOTES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE,IGNORE_SPACE,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_UNSIGNED_SUBTRACTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,PIPES_AS_CONCAT,REAL_AS_FLOAT,STRICT_ALL_TABLES,STRICT_TRANS_TABLES,ANSI,DB2,MAXDB,MSSQL,MYSQL323,MYSQL40,ORACLE,POSTGRESQL,TRADITIONAL
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: "graphcool"
            - name: MYSQL_DATABASE
              value: "graphcool"
          ports:
            - name: mysql-3306
              containerPort: 3306
          volumeMounts:
            - name: db-persistence
              readOnly: false
              mountPath: /var/lib/mysql
      volumes:
        - name: db-persistence
          gcePersistentDisk:
            readOnly: false
            fsType: ext4
            pdName: db-persistence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When applied, this definition schedules one Pod (&lt;code&gt;replicas: 1&lt;/code&gt;), with a running container based on the image &lt;code&gt;mysql:5.7&lt;/code&gt;, configures the environment (sets the password of the &lt;code&gt;root&lt;/code&gt; user to &lt;code&gt;graphcool&lt;/code&gt;) and mounts the disk &lt;code&gt;db-persistence&lt;/code&gt; to the path &lt;code&gt;/var/lib/mysql&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To actually apply that definition, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f database/deployment.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check if the actual Pod has been scheduled by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods --namespace prisma

NAME                        READY     STATUS    RESTARTS   AGE
database-3199294884-93hw4   1/1       Running   0          1m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs!&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the MySQL Service
&lt;/h2&gt;

&lt;p&gt;Before diving into this section, here's a short recap.&lt;/p&gt;

&lt;p&gt;Our MySQL database pod is now running and available within the cluster internally. Remember, Kubernetes assigns a local IP address to the &lt;code&gt;Pod&lt;/code&gt; so that another application could access the database.&lt;/p&gt;

&lt;p&gt;Now, imagine a scenario in which your database crashes. The cluster management system will take care of that situation and schedules the &lt;code&gt;Pod&lt;/code&gt; again. In this case, Kubernetes will assign a different IP address which results in crashes of your applications that are communicating with the database.&lt;/p&gt;

&lt;p&gt;To avoid such a situation, the cluster manager provides an internal DNS resolution mechanism. You have to use a different primitive, called &lt;code&gt;Service&lt;/code&gt;, to benefit from this. A service is an internal load balancer that is reachable via the &lt;code&gt;service name&lt;/code&gt;. Its task is to forward the traffic to your &lt;code&gt;Pod(s)&lt;/code&gt; and make it reachable across the cluster by its name.&lt;/p&gt;

&lt;p&gt;A service definition for our MySQL database would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: database
  namespace: prisma
spec:
  ports:
  - port: 3306
    targetPort: 3306
    protocol: TCP
  selector:
    stage: production
    name: database
    app: mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The definition would create an internal load balancer with the name &lt;code&gt;database&lt;/code&gt;. The service is then reachable by this name within the &lt;code&gt;prisma&lt;/code&gt; namespace. A little explanation about the &lt;code&gt;spec&lt;/code&gt; section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ports:&lt;/strong&gt; Here you map the service port to the actual container port. In this case the mapping is &lt;code&gt;3306&lt;/code&gt; to &lt;code&gt;3306&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selector:&lt;/strong&gt; Kind of a query. The load balancer identifies &lt;code&gt;Pods&lt;/code&gt; by selecting the ones with the specified labels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After creating this file, you can apply it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; database/service.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify that the service is up, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get services &lt;span class="nt"&gt;--namespace&lt;/span&gt; prisma

NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;    AGE
database   ClusterIP   10.3.241.165   &amp;lt;none&amp;gt;        3306/TCP   1m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prisma
&lt;/h2&gt;

&lt;p&gt;Okay, fair enough, the database is deployed. Next up: Deploying the actual Prisma server which is responsible for serving as an endpoint for the Prisma CLI.&lt;/p&gt;

&lt;p&gt;This application communicates with the already deployed &lt;code&gt;database&lt;/code&gt; service and uses it as the storage backend. Therefore, the Prisma server is a stateless application because it doesn't need any additional disk storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the Prisma Pod
&lt;/h3&gt;

&lt;p&gt;Deploying the actual Prisma server to run in a Pod is pretty straightforward. First of all you have to define the deployment definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: prisma
  namespace: prisma
  labels:
    stage: production
    name: prisma
    app: prisma
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        stage: production
        name: prisma
        app: prisma
    spec:
      containers:
        - name: prisma
          image: 'prismagraphql/prisma:1.1'
          ports:
            - name: prisma-4466
              containerPort: 4466
          env:
            - name: PORT
              value: "4466"
            - name: SQL_CLIENT_HOST_CLIENT1
              value: "database"
            - name: SQL_CLIENT_HOST_READONLY_CLIENT1
              value: "database"
            - name: SQL_CLIENT_HOST
              value: "database"
            - name: SQL_CLIENT_PORT
              value: "3306"
            - name: SQL_CLIENT_USER
              value: "root"
            - name: SQL_CLIENT_PASSWORD
              value: "graphcool"
            - name: SQL_CLIENT_CONNECTION_LIMIT
              value: "10"
            - name: SQL_INTERNAL_HOST
              value: "database"
            - name: SQL_INTERNAL_PORT
              value: "3306"
            - name: SQL_INTERNAL_USER
              value: "root"
            - name: SQL_INTERNAL_PASSWORD
              value: "graphcool"
            - name: SQL_INTERNAL_DATABASE
              value: "graphcool"
            - name: SQL_INTERNAL_CONNECTION_LIMIT
              value: "10"
            - name: CLUSTER_ADDRESS
              value: "http://prisma:4466"
            - name: BUGSNAG_API_KEY
              value: ""
            - name: ENABLE_METRICS
              value: "0"
            - name: JAVA_OPTS
              value: "-Xmx1G"
            - name: SCHEMA_MANAGER_SECRET
              value: "graphcool"
            - name: SCHEMA_MANAGER_ENDPOINT
              value: "http://prisma:4466/cluster/schema"
            - name: CLUSTER_PUBLIC_KEY
              value: "GENERATE VIA https://api.cloud.prisma.sh/"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration looks similar to the deployment configuration of the MySQL database. We tell Kubernetes that it should schedule one replica of the server and define the environment variables accordingly. As you can see, we use the name &lt;code&gt;database&lt;/code&gt; for each &lt;code&gt;SQL_*_HOST*&lt;/code&gt; variable. This works because of the fact that this &lt;code&gt;Pod&lt;/code&gt; will run in the same namespace as the database service – the Kubernetes DNS server makes that possible.&lt;/p&gt;

&lt;p&gt;Before applying that definition, we have to generate a public/private-keypair so that the CLI is able to communicate with this Prisma server. Head over to &lt;a href="https://api.cloud.prisma.sh/"&gt;https://api.cloud.prisma.sh/&lt;/a&gt; and execute the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  generateKeypair {
    public
    private
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to store those values in a safe place! Now, copy the &lt;code&gt;public&lt;/code&gt; key and paste it into the &lt;code&gt;value&lt;/code&gt; of the &lt;code&gt;CLUSTER_PUBLIC_KEY&lt;/code&gt; environment variable in &lt;code&gt;prisma/deployment.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Afterwards, we are ready to apply that deployment definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; prisma/deployment.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As in the previous sections: In order to check that the Prisma server has been scheduled on the Kubernetes cluster, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;--namespace&lt;/span&gt; prisma

NAME                        READY     STATUS    RESTARTS   AGE
database-3199294884-93hw4   1/1       Running   0          5m
prisma-1733176504-zlphg     1/1       Running   0          1m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yay! The Prisma server is running! Off to our next and last step:&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the Prisma Service
&lt;/h3&gt;

&lt;p&gt;Okay, cool, the database &lt;code&gt;Pod&lt;/code&gt; is running and has an internal load balancer in front of it, the Prisma server &lt;code&gt;Pod&lt;/code&gt; is also running, but is missing the load balancer a.k.a. &lt;code&gt;Service&lt;/code&gt;. Let's fix that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: prisma
  namespace: prisma
spec:
  ports:
  - port: 4466
    targetPort: 4466
    protocol: TCP
  selector:
    stage: production
    name: prisma
    app: prisma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply it via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; prisma/service.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, done! The Prisma server is now reachable within the Kubernetes cluster via its name &lt;code&gt;prisma&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's all. Prisma is running on Kubernetes!&lt;/p&gt;

&lt;p&gt;The last step is to configure your local &lt;code&gt;Prisma CLI&lt;/code&gt; so that you can communicate with the instance on the Kubernetes Cluster.&lt;/p&gt;

&lt;p&gt;The upcoming last step is also necessary if you want to integrate &lt;code&gt;prisma deploy&lt;/code&gt; into your CI/CD process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration of the Prisma CLI
&lt;/h2&gt;

&lt;p&gt;The Prisma server is running on the Kubernetes cluster and has an internal load balancer. This is a sane security default, because you won't expose the Prisma server to the public directly. Instead, you would develop a GraphQL API and deploy it to the Kubernetes cluster as well.&lt;/p&gt;

&lt;p&gt;You may ask: "Okay, but how do I execute &lt;code&gt;prisma deploy&lt;/code&gt; in order to populate my data model when I'm not able to communicate with the Prisma server directly?&lt;code&gt;. That is indeed a very good question!&lt;/code&gt;kubectl` comes with a mechanism that allows forwarding a local port to an application that lives on the Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;So every time you want to communicate with your Prisma server on the Kubernetes cluster, you have to perform the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;kubectl get pods --namespace prisma&lt;/code&gt; to identify the pod name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl port-forward --namespace prisma &amp;lt;the-pod-name&amp;gt; 4467:4466&lt;/code&gt; – This will forward from &lt;code&gt;127.0.0.1:4467&lt;/code&gt; -&amp;gt; &lt;code&gt;kubernetes-cluster:4466&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Prisma server is now reachable via &lt;code&gt;http://localhost:4467&lt;/code&gt;. With this in place, we can configure the CLI:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
prisma cluster add&lt;/p&gt;

&lt;p&gt;? Please provide the cluster endpoint &lt;a href="http://localhost:4467"&gt;http://localhost:4467&lt;/a&gt;&lt;br&gt;
? Please provide the cluster secret &lt;br&gt;
? Please provide a name for your cluster kubernetes&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Okay, you made it! Congratulations, you have successfully deployed a Prisma server to a production Kubernetes cluster environment.&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>graphql</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Docker: Restricting in- and outbound network traffic</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Tue, 10 Oct 2017 14:58:36 +0000</pubDate>
      <link>https://dev.to/andre/docker-restricting-in--and-outbound-network-traffic-67p</link>
      <guid>https://dev.to/andre/docker-restricting-in--and-outbound-network-traffic-67p</guid>
      <description>&lt;p&gt;Imagine a scenario in which you might have a stinky module deep in your dependency graph. A dependency that wants to do something evil – a malware. "But I'm isolating everything in a Docker container at runtime!", you might say. Indeed, that helps when the evil module tries to mess up with your filesystem or other host related aspects. But what if the module wants to phone home?”&lt;/p&gt;

&lt;p&gt;I thought about that problem today and want to share my approach with you. Before I headed straight into tinkering, I created the following acceptance criteria:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The container should accept in- and outbound traffic from and to a known network&lt;/li&gt;
&lt;li&gt;The container should block in- and outbound traffic from and to all other networks&lt;/li&gt;
&lt;li&gt;The application within the container should run as a non-privileged user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;"A privileged user is necessary for restricting network traffic." was my first thought which conflicts with the third acceptance criteria. Meh!&lt;/p&gt;

&lt;p&gt;After implementing some test probes, I settled with the following solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provisioning of a base image which ships with a non-privileged user and an &lt;code&gt;ENTRYPOINT&lt;/code&gt; script&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ENTRYPOINT&lt;/code&gt; script gets executed when the container starts, defines the &lt;a href="http://www.netfilter.org/projects/iptables/index.html"&gt;iptables&lt;/a&gt; rules and starts the given application as the configured non-privileged user afterwards.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's have a look at the actual solution. The &lt;strong&gt;Dockerfile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:8-alpine&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="AndrÃ© KÃ¶nig &amp;lt;andre.koenig@gmail.com&amp;gt;"&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--update&lt;/span&gt; curl iptables &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; app &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; app app

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; entrypoint.sh /entrypoint.sh&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/entrypoint.sh", "--"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, pretty straight forward: Using a base image – in this case the Node.js 8 Alpine image, adding a new user group and creating a new user. The second part copies the &lt;code&gt;entrypoint.sh&lt;/code&gt; script into the container and defines it as an &lt;a href="https://docs.docker.com/engine/reference/builder/#entrypoint"&gt;ENTRYPOINT&lt;/a&gt;. Nothing special here. So let's define the actual &lt;code&gt;entrypoint.sh&lt;/code&gt;:&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="c"&gt;#!/usr/bin/env sh&lt;/span&gt;

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# iptables configuration&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# The following allows in- and outbound traffic&lt;/span&gt;
&lt;span class="c"&gt;# within a certain `CIDR` (default: `192.168.0.0/24`),&lt;/span&gt;
&lt;span class="c"&gt;# but blocks all other network traffic.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="nv"&gt;ACCEPT_CIDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ALLOWED_CIDR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;192&lt;/span&gt;&lt;span class="p"&gt;.168.0.0/24&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

iptables &lt;span class="nt"&gt;-A&lt;/span&gt; INPUT &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;$ACCEPT_CIDR&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class="nt"&gt;-A&lt;/span&gt; INPUT &lt;span class="nt"&gt;-j&lt;/span&gt; DROP
iptables &lt;span class="nt"&gt;-A&lt;/span&gt; OUTPUT &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$ACCEPT_CIDR&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
iptables &lt;span class="nt"&gt;-A&lt;/span&gt; OUTPUT &lt;span class="nt"&gt;-j&lt;/span&gt; DROP

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# After configuring `iptables` as root, execute&lt;/span&gt;
&lt;span class="c"&gt;# the passed command as the non-privileged `app` user.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; app sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage examples
&lt;/h2&gt;

&lt;p&gt;After bulding the image via &lt;code&gt;docker build -t node-sandbox .&lt;/code&gt;, let's test drive this new sandboxed environment.&lt;/p&gt;

&lt;p&gt;For example, in order to test if there is really no outbound traffic, try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; node-sandbox &lt;span class="s2"&gt;"curl https://google.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; should give up after some time and you will see an &lt;code&gt;curl: (6) Could not resolve host: google.com&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;On the other hand, communicating with a system in your local network should work. So if you live in the &lt;code&gt;192.168.0.0/24&lt;/code&gt; network and you have something running on &lt;code&gt;192.168.0.1&lt;/code&gt; (maybe your wifi router), you should see a response when executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; node-sandbox &lt;span class="s2"&gt;"curl http://192.168.0.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attentive reader might have noticed that the &lt;code&gt;entrypoint.sh&lt;/code&gt; checks if the environment variable &lt;code&gt;ALLOWED_CIDR&lt;/code&gt; is set and takes the &lt;code&gt;CIDR&lt;/code&gt; notated network instead of the fallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"ALLOWED_CIDR=10.0.0.0/8"&lt;/span&gt; node-sandbox &lt;span class="s2"&gt;"curl http://10.0.0.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;One of my clients had to tranform highly sensible user data within a Node.js-based application over and over again. Because of high security standards within that organization, they anticipated an isolated network environment in which no   possible evil dependency could ever reach out and send sensible information to an external system. Despite the fact that the application doesn't run within a container orchestrator where you have fine-grained control over the network stack, but on a user machine, this seems to be a solution that works quite well. If you face a similar situation, this approach might assist you and I'm happy to read your views. &lt;/p&gt;

</description>
      <category>firewall</category>
      <category>security</category>
      <category>docker</category>
      <category>linux</category>
    </item>
    <item>
      <title>react-apollo: An approach to handle errors globally</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Mon, 02 Oct 2017 16:54:01 +0000</pubDate>
      <link>https://dev.to/andre/react-apollo-an-approach-to-handle-errors-globally-jg</link>
      <guid>https://dev.to/andre/react-apollo-an-approach-to-handle-errors-globally-jg</guid>
      <description>&lt;p&gt;Well, I had quite a journey today and I would like to share it with you. I'm – like most of you – a huge fan of &lt;a href="http://graphql.org/"&gt;GraphQL&lt;/a&gt; and the &lt;a href="https://www.apollodata.com/"&gt;Apollo Stack&lt;/a&gt;. Those two technologies + React: declarative rendering + declarative data fetching â¤ï¸ - Is there anything that would make a dev happier? I guess there are many things, but anyways. One thing that bothered me a lot today was handling errors globally. ðŸ˜¤&lt;/p&gt;

&lt;p&gt;Imagine the following scenario: An unexpected error occurred. Something really bad. The UI can't and shouldn't recover from that state. You would love to display a completely different UI which informs the user about that case. The Apollo client, or the &lt;code&gt;react-apollo&lt;/code&gt; binding to be precisely, is pretty good when it comes to handling occurred errors on a local level. Something in the vein of: You have a component that "binds" to a GraphQL query and whenever an error occurred you will display something different within &lt;em&gt;that&lt;/em&gt; component:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;compose&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recompose&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-apollo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ErrorHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components&lt;/span&gt;&lt;span class="dl"&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;NewsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
    query news {
      id
      name
    }
  `&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)(({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ErrorHandler&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;news&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;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;entry&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;)
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is nothing wrong with that approach, except that it doesn't fulfil our aspired scenario in which we want to display an UI the user can't "escape" from. How can we achieve that then?&lt;/p&gt;

&lt;h2&gt;
  
  
  Afterwares to the rescue!
&lt;/h2&gt;

&lt;p&gt;The Apollo Client comes with a mechanism called &lt;a href="http://dev.apollodata.com/core/network.html#networkInterfaceAfterware"&gt;Afterware&lt;/a&gt;. An &lt;code&gt;Afterware&lt;/code&gt; gives you the possibility to hook you right into the network layer of the Apollo client. It is a function that gets executed whenever a response comes from the server and gets processed by the client. An example:&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;// graphql/index.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createNetworkInterface&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-apollo&lt;/span&gt;&lt;span class="dl"&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;createClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;endpointUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uri&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;networkInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createNetworkInterface&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;networkInterface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useAfter&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt;
    &lt;span class="nx"&gt;applyAfterware&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="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Do something with the response ...&lt;/span&gt;
      &lt;span class="nx"&gt;next&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;networkInterface&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before diving into how to handle the actual error, I would like to complete the example by defining how to create the actual client and use it in your app. The following would be your entry component that bootstraps your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-apollo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./graphql&lt;/span&gt;&lt;span class="dl"&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;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app&lt;/span&gt;&lt;span class="dl"&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;endpointUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.graph.cool/...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ApolloProvider&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ApolloProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So that is this. Creating the client and passing it to the &lt;code&gt;ApolloProvider&lt;/code&gt;. Now what? I promised you that we wan't to display a scene which doesn't allow the user to interact with the app. After some tinkering I came to the conclusion that there is a simple solution for that. So here is the dopey idea: Let's pass an additional function to the &lt;code&gt;createClient&lt;/code&gt; function, called &lt;code&gt;onError&lt;/code&gt; which takes an error object and performs a complete new &lt;code&gt;render&lt;/code&gt; on the &lt;code&gt;$app&lt;/code&gt; DOM node. That would allow us to unmount the corrupt UI and render a different component for displaying the respective error case to the user ðŸ¿&lt;/p&gt;

&lt;p&gt;First of all: Let's adjust the bootstrapping of the app by defining the &lt;code&gt;onError&lt;/code&gt; function and passing it to the &lt;code&gt;createClient&lt;/code&gt; call:&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;// index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-apollo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./graphql&lt;/span&gt;&lt;span class="dl"&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;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app&lt;/span&gt;&lt;span class="dl"&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;endpointUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.graph.cool/...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyErrorHandler&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ApolloProvider&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ApolloProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Afterwards, we have to adjust our &lt;code&gt;Afterware&lt;/code&gt; so that it calls that passed &lt;code&gt;onError&lt;/code&gt; function whenever the server responds with errors:&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;// graphql/index.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createNetworkInterface&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-apollo&lt;/span&gt;&lt;span class="dl"&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;createClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;endpointUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onError&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;networkInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createNetworkInterface&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;networkInterface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useAfter&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt;
    &lt;span class="nx"&gt;applyAfterware&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="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&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="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`A fatal error occurred`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;next&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;networkInterface&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wohoo! That's it! From now on, your application would display your &lt;code&gt;&amp;lt;MyErrorHandler /&amp;gt;&lt;/code&gt; whenever an error occurred. Mission completed!&lt;/p&gt;

&lt;p&gt;Would be great when we could use &lt;a href="https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html"&gt;error boundaries&lt;/a&gt; which has been introduced in &lt;em&gt;React 16&lt;/em&gt;, but that is not possible due the not "throwing nature" of the Apollo client (which is a good thing when you want to have fine-grained error handling capabilities).&lt;/p&gt;

&lt;p&gt;That is it from me for now. Hope you enjoyed the ride and maybe this approach is also useful for you :)&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>react</category>
      <category>graphql</category>
      <category>apollo</category>
    </item>
    <item>
      <title>What is the best mechanical keyboard out there?</title>
      <dc:creator>André König</dc:creator>
      <pubDate>Thu, 07 Sep 2017 14:19:38 +0000</pubDate>
      <link>https://dev.to/andre/what-is-the-best-mechanical-keyboard-out-there</link>
      <guid>https://dev.to/andre/what-is-the-best-mechanical-keyboard-out-there</guid>
      <description>&lt;p&gt;First of all: I have to admit that I'm more or less a newbie when it comes to mechanical keyboards.&lt;/p&gt;

&lt;p&gt;There are a lot of engineers who seems to favour this kind of keyboard over the others. A couple of weeks ago I tried one by myself and was kind of flashed. It feels so much better than the common Apple keyboards I'm usually hacking on. Therefore, I did some research and found the &lt;a href="https://codekeyboards.com/"&gt;CODE&lt;/a&gt; keyboard which seems to be a nice fit.&lt;/p&gt;

&lt;p&gt;Before buying one, I thought it might be a good idea to ask all of you: What keyboard do you feel most comfortable with?&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
  </channel>
</rss>
