<?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: Lenra</title>
    <description>The latest articles on DEV Community by Lenra (@lenra).</description>
    <link>https://dev.to/lenra</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%2Forganization%2Fprofile_image%2F5588%2F9e503fce-3100-420d-8e2d-060a06d72531.png</url>
      <title>DEV Community: Lenra</title>
      <link>https://dev.to/lenra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lenra"/>
    <language>en</language>
    <item>
      <title>Join us now on Lenra, a unique place to create a cross-platform app that scales automatically to follow your users growth.</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Tue, 06 Jun 2023 10:06:00 +0000</pubDate>
      <link>https://dev.to/lenra/join-us-now-on-lenra-a-unique-place-to-create-a-cross-platform-app-that-scales-automatically-to-follow-your-users-growth-4eic</link>
      <guid>https://dev.to/lenra/join-us-now-on-lenra-a-unique-place-to-create-a-cross-platform-app-that-scales-automatically-to-follow-your-users-growth-4eic</guid>
      <description>&lt;p&gt;Hey, you! Yeah, you...&lt;br&gt;
Have you ever wanted to make a difference in the world, but you don't have the money or the resources to do it? &lt;br&gt;
Well, I'm here to tell you that you can still make a difference without breaking the bank. How, you ask? By contributing to our open source project, of course!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io"&gt;Contributing to Lenra&lt;/a&gt;, an app creation platform,  isn't just about making a difference. It's also about learning new skills. Whether you're a developer, a designer, or just someone who's interested in tech, you can learn a lot from collaborating with others on our project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.lenra.io/"&gt;Lenra&lt;/a&gt; offers a range of benefits that can help developers simplify the app development and hosting process, while ensuring the privacy and security of user data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WWjVK8Q1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbbufwflmwlml6nflec1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WWjVK8Q1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbbufwflmwlml6nflec1.jpg" alt="Image description" width="750" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are some insights : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Faster app development:&lt;/strong&gt; Lenra provides an all-in-one platform with optimized dev tools, which can help developers accelerate the development process and reduce time-to-market&lt;a href="https://www.lenra.io/"&gt;[1]&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Simplified app hosting:&lt;/strong&gt; Lenra offers a range of hosting services that can simplify app deployment and management, including automatic scaling and reduced carbon footprint&lt;a href="https://www.lenra.io/usecases.html"&gt;[2]&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Enhanced data privacy:&lt;/strong&gt; Lenra is GDPR-compliant and offers a range of security features, including malware protection and a Single Sign-On (SSO) system, which can help ensure the privacy and security of user data&lt;a href="https://www.lenra.io/"&gt;[3]&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Ethical development:&lt;/strong&gt; Lenra is a Big Tech-free platform with sober code, hosted within the European Union, which can help developers support ethical development practices&lt;a href="https://www.lenra.io/manifesto.html"&gt;[4]&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Open-source and transparent:&lt;/strong&gt; Lenra is an open-source platform that allows anyone to take ownership of the platform, and offers transparency in its development and operations&lt;a href="https://www.lenra.io/"&gt;[5]&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k0KiZLNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxskmpripwccaq9tysfa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k0KiZLNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxskmpripwccaq9tysfa.png" alt="Image description" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
Contribute now and take your part of the new world ;)&lt;/p&gt;

&lt;h4&gt;
  
  
  Sources:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://www.lenra.io/"&gt;https://www.lenra.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://www.lenra.io/usecases.html"&gt;https://www.lenra.io/usecases.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://www.lenra.io/"&gt;https://www.lenra.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://www.lenra.io/manifesto.html"&gt;https://www.lenra.io/manifesto.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://www.lenra.io/"&gt;https://www.lenra.io/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>github</category>
      <category>opensource</category>
      <category>cli</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why YAML is better than JSON (read before screaming)</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Fri, 17 Mar 2023 09:20:10 +0000</pubDate>
      <link>https://dev.to/lenra/why-yaml-is-better-than-json-read-before-screaming-39m8</link>
      <guid>https://dev.to/lenra/why-yaml-is-better-than-json-read-before-screaming-39m8</guid>
      <description>&lt;p&gt;You have probably seen or used the YAML format in configuration files.&lt;br&gt;
YAML (a recursive acronym for “YAML Ain’t Markup Language”) is a human-friendly data serialization language for all programming languages, like the JSON format.&lt;/p&gt;



&lt;p&gt;The YAML files are mostly written using the Python-style indentation to indicate nesting such as the following example of a &lt;a href="https://github.com/lenra-io/dofigen"&gt;Dofigen&lt;/a&gt; file:&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;# An anchor&lt;/span&gt;
&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;image&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docker.io/bitnami/node:18"&lt;/span&gt;
&lt;span class="c1"&gt;# A string field&lt;/span&gt;
&lt;span class="na"&gt;workdir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/app&lt;/span&gt;
&lt;span class="c1"&gt;# An object list&lt;/span&gt;
&lt;span class="na"&gt;builders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# An object&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;module-loader&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*image&lt;/span&gt;
    &lt;span class="na"&gt;workdir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp/module&lt;/span&gt;
    &lt;span class="na"&gt;adds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;package.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;package-lock.json&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i --production --cache /tmp/cache&lt;/span&gt;
    &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/tmp/cache&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;builder&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*image&lt;/span&gt;
    &lt;span class="na"&gt;workdir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp/app&lt;/span&gt;
    &lt;span class="na"&gt;adds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i --cache /tmp/cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
    &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/tmp/cache&lt;/span&gt;
&lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;module-loader&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp/module/&lt;/span&gt;
    &lt;span class="na"&gt;destination&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;builder&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp/app/dist/&lt;/span&gt;
    &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist/&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;builder&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp/app/resources/&lt;/span&gt;
    &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;resources/&lt;/span&gt;
&lt;span class="c1"&gt;# A string list&lt;/span&gt;
&lt;span class="na"&gt;cmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;start&lt;/span&gt;
&lt;span class="c1"&gt;# An integer list&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="m"&gt;3000&lt;/span&gt;
&lt;span class="na"&gt;ignores&lt;/span&gt;&lt;span class="pi"&gt;:&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="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!/*.json"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!/src/"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!/resources/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may say: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OK, the YAML is great and very readable but how could it be &lt;strong&gt;better&lt;/strong&gt; than JSON ?&lt;br&gt;
They are just two different formats.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's true, but I will show you how YAML is at least as good as JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  YAML is at least as good as JSON
&lt;/h2&gt;

&lt;p&gt;The YAML format permits many ways to define the data.&lt;br&gt;
We will see here the different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;strings&lt;/li&gt;
&lt;li&gt;arrays/list&lt;/li&gt;
&lt;li&gt;objects/strutures&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  strings
&lt;/h3&gt;

&lt;p&gt;The basic string description is just writing the string:&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;myString&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My super string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to disambiguate other data types like numbers or booleans, we can define the string by surrounding the value with simple quotes(&lt;code&gt;'&lt;/code&gt;) or double quotes(&lt;code&gt;"&lt;/code&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;myString&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;super&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;string"&lt;/span&gt;
&lt;span class="na"&gt;alsoString&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;10'&lt;/span&gt;
&lt;span class="na"&gt;stringNotBoolean&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For multiline strings we also can use two specific descriptions:&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;myString&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;My super &lt;/span&gt;
  &lt;span class="s"&gt;multiline string&lt;/span&gt;

  &lt;span class="s"&gt;Second line&lt;/span&gt;
&lt;span class="na"&gt;otherString&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;The other super multiline string&lt;/span&gt;
  &lt;span class="s"&gt;Second line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at &lt;a href="https://yaml-multiline.info/"&gt;this website&lt;/a&gt; to read more about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  arrays/lists
&lt;/h3&gt;

&lt;p&gt;The main array description in YAML is the next one:&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;myArray&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;My string value&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But YAML also permits the use of another syntax, by surrounding the array elements with brackets (&lt;code&gt;[&lt;/code&gt; and &lt;code&gt;]&lt;/code&gt;), very useful for short or empty arrays:&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;myShortArray&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;first&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;second&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;emptyArray&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  objects/structures
&lt;/h3&gt;

&lt;p&gt;The main object description in YAML is the following one:&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My string&lt;/span&gt;
&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;
&lt;span class="na"&gt;subobject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;nestedField&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That would result to the next JSON object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subobject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nestedField"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The value"&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;But the YAML format also permits the use of braces (&lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt;) to surround the object fields and they can be separated by a comma+space instead of a new line.&lt;br&gt;
It also permits the use of simple quotes(&lt;code&gt;'&lt;/code&gt;) or double quotes(&lt;code&gt;"&lt;/code&gt;) arround the field name.&lt;br&gt;
Here is the same object with this syntax:&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="pi"&gt;{&lt;/span&gt;
  &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name'&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;My string&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;age"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;24&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;subobject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;nestedField&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;The value&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Merged YAML secondary format
&lt;/h3&gt;

&lt;p&gt;Do you see where I'm going with this ?&lt;/p&gt;

&lt;p&gt;Here is another way to describe the initial YAML example, but using the syntaxes seen previously:&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="pi"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;# An anchor&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;image&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docker.io/bitnami/node:18"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;# A string field&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workdir"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/app"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;# An object list&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;builders"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# An object&lt;/span&gt;
    &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;module-loader"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*image&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workdir"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/module"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adds"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;package.json"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;package-lock.json"&lt;/span&gt;
      &lt;span class="pi"&gt;],&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;script"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;i&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--production&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--cache&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/tmp/cache"&lt;/span&gt; &lt;span class="pi"&gt;],&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;caches"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/cache"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="pi"&gt;},&lt;/span&gt;
    &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;builder"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*image&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;workdir"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/app"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adds"&lt;/span&gt;&lt;span class="pi"&gt;:&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="pi"&gt;],&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;script"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;i&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--cache&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;/tmp/cache"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;build"&lt;/span&gt;
      &lt;span class="pi"&gt;],&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;caches"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/cache"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="pi"&gt;],&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;artifacts"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
    &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;builder"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;module-loader"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/module/"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;destination"&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="pi"&gt;},&lt;/span&gt;
    &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;builder"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;builder"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/app/dist/"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;destination"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dist/"&lt;/span&gt;
    &lt;span class="pi"&gt;},&lt;/span&gt;
    &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;builder"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;builder"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp/app/resources/"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;destination"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resources/"&lt;/span&gt;
    &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="pi"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;# A string list&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cmd"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start"&lt;/span&gt; &lt;span class="pi"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;# An integer list&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ports"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;3000&lt;/span&gt; &lt;span class="pi"&gt;],&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ignores"&lt;/span&gt;&lt;span class="pi"&gt;:&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="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!/*.json"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!/src/"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!/resources/"&lt;/span&gt;
  &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does it look familiar ?&lt;br&gt;
Yes, the YAML format is fully compatible with JSON data.&lt;/p&gt;

&lt;p&gt;But there are still some elements that you can't find in JSON format.&lt;/p&gt;
&lt;h2&gt;
  
  
  YAML additional features
&lt;/h2&gt;



&lt;p&gt;The YAML format also has many interesting additional features, let's take a look at some of those I use in my projects.&lt;/p&gt;
&lt;h3&gt;
  
  
  Comments
&lt;/h3&gt;

&lt;p&gt;One of the features that I miss the most in JSON files is the comments.&lt;br&gt;
How many times I tried to comment a dependency in a &lt;code&gt;package.json&lt;/code&gt; file or a configuration...&lt;/p&gt;

&lt;p&gt;In YAML, you can comment a line by just adding a hashtag (&lt;code&gt;#&lt;/code&gt;) before the line content.&lt;br&gt;
So simple !&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;# my comment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Anchors
&lt;/h3&gt;

&lt;p&gt;YAML format also lets you avoid repeating data in your configuration files thanks to the anchors.&lt;br&gt;
With this feature you can define an anchor (&lt;code&gt;&amp;amp;&lt;/code&gt;) by setting its name before a value (of any type).&lt;br&gt;
You can then use an alias (&lt;code&gt;*&lt;/code&gt;) as value of another field (later in the same YAML file).&lt;/p&gt;

&lt;p&gt;The anchors let you change a value used many times at a single point like from Docker image in the initial example:&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;# An anchor&lt;/span&gt;
&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;image&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docker.io/bitnami/node:18"&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;builders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# An object&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;module-loader&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*image&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is even more useful for objects and arrays.&lt;/p&gt;

&lt;p&gt;YAML anchors also let you extend and override an object for a new value by entering &lt;code&gt;&amp;lt;&amp;lt;:&lt;/code&gt; before the alias.&lt;br&gt;
Here is an example with a builder:&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="nl"&gt;&amp;amp;base&lt;/span&gt;
&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docker.io/bitnami/node:18"&lt;/span&gt;
&lt;span class="na"&gt;workdir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/app&lt;/span&gt;
&lt;span class="na"&gt;builders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*base&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;module-loader&lt;/span&gt; &lt;span class="c1"&gt;# extension to add the name&lt;/span&gt;
    &lt;span class="na"&gt;workdir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp/module&lt;/span&gt; &lt;span class="c1"&gt;# override the workdir&lt;/span&gt;
    &lt;span class="na"&gt;adds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;package.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;package-lock.json&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i --production --cache /tmp/cache&lt;/span&gt;
    &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/tmp/cache&lt;/span&gt;
    &lt;span class="na"&gt;builders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# override the build to null to avoid circular references&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feature is also very useful but could lead to less readable files if not done wisely.&lt;/p&gt;

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

&lt;p&gt;We have seen previously that the YAML format is fully compatible with the JSON one and that it has many additionnal features, but I wrote this article focusing on the human-friendly part of those languages.&lt;br&gt;
This is not the only important aspect for a format.&lt;br&gt;
The permissivity of the YAML format makes it more readable and easy to use (at least to me ^^), but it also can make it less efficient to process in a program...&lt;/p&gt;

&lt;p&gt;To look for all the additionnal features see the &lt;a href="https://yaml.org/spec/1.2.2/"&gt;full specification (at the current date)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/YAML"&gt;https://en.wikipedia.org/wiki/YAML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yaml.org/"&gt;https://yaml.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.educative.io/blog/advanced-yaml-syntax-cheatsheet"&gt;https://www.educative.io/blog/advanced-yaml-syntax-cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yaml-multiline.info/"&gt;https://yaml-multiline.info/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>yaml</category>
      <category>json</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Are you ready to go green ?</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Thu, 16 Mar 2023 10:28:26 +0000</pubDate>
      <link>https://dev.to/lenra/are-you-ready-to-go-green--1hlo</link>
      <guid>https://dev.to/lenra/are-you-ready-to-go-green--1hlo</guid>
      <description>&lt;h2&gt;
  
  
  Do you consider the environmental impact of the applications you are developing?
&lt;/h2&gt;

&lt;p&gt;The world becomes increasingly concerned about climate change, and most businesses are looking for ways to reduce their carbon footprint and promote sustainability. &lt;br&gt;
However, I don't feel like there's massive changes in the tech game in order to switch habits and search for a more virtuous circle. &lt;br&gt;
The energy consumption and carbon emissions of applications are significant, and developers have an important role to play in creating low carbon apps.&lt;/p&gt;

&lt;p&gt;But do you really care ? Are you open to using alternative technologies or tools to reduce the carbon footprint of your applications?  &lt;/p&gt;

&lt;h2&gt;
  
  
  Where are you in the tree ? (imagine the tree is "green technology")
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AA7wEWze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gakfitrfcsl2vsdbzm4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AA7wEWze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gakfitrfcsl2vsdbzm4.png" alt="Image description" width="595" height="842"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wherever you see yourself in that tree, I would love to know why... What's on your mind ? &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Do your data smell gas ?!</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Tue, 06 Dec 2022 10:11:19 +0000</pubDate>
      <link>https://dev.to/lenra/do-your-data-smell-gas--f21</link>
      <guid>https://dev.to/lenra/do-your-data-smell-gas--f21</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wqVxRfES--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qgtesexu8x8g2wr9aww.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wqVxRfES--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qgtesexu8x8g2wr9aww.jpg" alt="Image description" width="299" height="169"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Digital sovereignty called into question&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the implementation of the GDPR in 2018, the European Union has equipped itself with strong legislation to protect the privacy of its citizens’ data. This advance has brought order to the abusive practices that led to the mass surveillance scandals by U.S. intelligence agencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Europe’s energy dependence on the scale&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Europe’s hard-won digital sovereignty appears to be challenged by a shift in the balance of power. Indeed, the Russian-Ukrainian conflict has reshuffled the cards in the international distribution of energy resources. This new context has made it necessary for the EU to seek new sources of supply. The United States needed no less to seize this opportunity and renegotiate the issue of the sovereignty of European personal data.&lt;br&gt;
Thus, the announcement of an energy alliance between Europe and the United States on March 25, 2022 was followed seven months later (on September 7) by another announcement on the regulatory framework for data transfer on both sides of the Atlantic. This is a resumption of the discussions since the European Court of Justice invalidated the Privacy Shield (July 16, 2020). It is difficult not to make the link between these two events to explain the loss of European ground on this highly sensitive issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A look back at a long-standing legal tug-of-war&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Safe Harbor agreement on data transfer between the EU and the United States, which dates back to the 2000s, was annulled in 2015 by the EU Court of Justice. The lack of data protection for European citizens was at issue in this decision.&lt;br&gt;
A new agreement, the Privacy Shield, was drawn up in July 2016 and invalidated 4 years later for the same reasons. The implementation of the famous RGPD in 2018 appears to be a protective bulwark against the shameless exploitation of European data by American digital giants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The persistence of American pressure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Americans react quickly to this strong stance by the EU. Shortly afterwards, they put in place the Cloud Act (Clarifying Lawful Overseas Use of Data Act) to circumvent Article 5 of the GDPR. With this act, the American authorities assume the right to obtain data stored on American servers, regardless of their origin (thus including abroad).&lt;br&gt;
The exploitation of personal data is the core business of Big Tech, which is not ready to give it up. However, they find themselves stuck with conflicting legislation in this showdown between the two political entities. And despite the dominant position of the American digital behemoths, the European pressure to impose heavy financial penalties or ban the use of data is still hovering.&lt;br&gt;
Faced with the inability to reach an agreement on this issue and break the legal deadlock, Meta waved the threat of removing Facebook and Instagram from the European continent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the end,&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The United States were able to deftly exploit the situation by asserting the best interests of its national security. The coincidence with a U.S. liquid gas delivery agreement leaves no one fooled by the maneuver. However, the decree still has to be submitted to the European Commission for approval, which is not likely to happen before the spring of 2023. The suspense remains.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>database</category>
      <category>community</category>
    </item>
    <item>
      <title>Do's &amp; don't's of writing Elixir</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Tue, 15 Nov 2022 08:18:33 +0000</pubDate>
      <link>https://dev.to/lenra/dos-donts-of-writing-elixir-5dd0</link>
      <guid>https://dev.to/lenra/dos-donts-of-writing-elixir-5dd0</guid>
      <description>&lt;p&gt;In this article, we are going to explore do's and don't's of writing Elixir code. We will briefly learn the key challenges of switching from other languages to Elixir. For simplicity, we will write all the examples and code snippets using Python &amp;amp; Elixir and learn some common mistakes that programmers often do when switching to Elixir from a different programming language.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Elixir?
&lt;/h2&gt;

&lt;p&gt;Elixir is a functional progamming language that runs on the powerful Erlang VM. Elixir takes full advantage of the VM and provides the perfect environment to the developer to build fault tolerant,low-latency, distributed systems.&lt;/p&gt;

&lt;p&gt;According to stackoverflow's 2022 Developer Survey, it is the Second &lt;a href="https://survey.stackoverflow.co/2022/#section-most-loved-dreaded-and-wanted-programming-scripting-and-markup-languages"&gt;most loved Programming language&lt;/a&gt; of the Year.&lt;/p&gt;

&lt;p&gt;The Elixir Community is growing as more and more people &amp;amp; companies adopting elixir to their code base.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Key Challenges of Switching to Elixir
&lt;/h2&gt;

&lt;p&gt;Unlike other functional programming languages such as Erlang, Clojure, etc. Elixir has a more beginner friendly syntax. This also opens the door to bring the baggage of other programming languages to Elixir.&lt;/p&gt;

&lt;p&gt;For example, Python programmers with no previous functional programming experience might attempt to apply coding patterns of Object Oriented programming that are not suitable for Functional Programming. Even though, they might get away with writing codes that are more "Pythonic" than "Elixir". It will hinder their growth &amp;amp; productivity in the long term.&lt;/p&gt;

&lt;p&gt;The lack of functional programming knowledge will also prevent them from taking advantage of various functional programming paradigms. It will also challenge their core concepts in at least three different layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Functional way of thinking (i.e. immutability/streams/transformation/pipeline)&lt;/li&gt;
&lt;li&gt;OTP way of thinking (i.e. concurrency, fault-tolerence, distributed system)&lt;/li&gt;
&lt;li&gt;Patterns and Pipes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So they will have to unlearn what they already know and think with a fresh perspective. This initial step is relatively hard but once, they master the concepts they will become productive in no time.&lt;/p&gt;

&lt;p&gt;Now let's take a look at a few examples:&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutable vs Immutable
&lt;/h2&gt;

&lt;p&gt;In a Python environment, Variables or objects are mutable. Consider the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can't reliably say, what will be the output of the print statement without looking at the source code of function &lt;code&gt;do_something&lt;/code&gt;. In Python, Lists are passed as reference, so it is possible that the &lt;code&gt;do_something&lt;/code&gt; function can alter the original &lt;code&gt;my_list&lt;/code&gt; e.g. add something to the list or remove a thing or two. If we think in concurrency or parallel programming this could lead to unintended bugs. Two processes accessing the same object can get different values based on execution order or moment.&lt;/p&gt;

&lt;p&gt;In Elixir, this is not an issue cause, variables are always immutable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the output of &lt;code&gt;IO.inspect()&lt;/code&gt; is guaranteed to get the list &lt;code&gt;[1, 2, 3]&lt;/code&gt;. In other words, the &lt;code&gt;do_something()&lt;/code&gt; function can not modify the my_list variable. Even if we spawn hundreds or thousands of processes and access &lt;code&gt;my_list&lt;/code&gt; all of those processes will get the same value of &lt;code&gt;my_list&lt;/code&gt;. This is also true for complex data such as Nested List of Lists, Maps, or Database Records, etc.&lt;/p&gt;

&lt;p&gt;Mastering the concepts of immutability is essential to write Good Elixir Code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nested Function Calls vs Piping
&lt;/h2&gt;

&lt;p&gt;Nested function calls are common in most programming languages. When we want to pass the return value of a function as an agrument to another function the nesting occurs. it is more like a series of transformation to data. Elixir also allows nested function calls to transform data. Consider the below example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_flavor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredients&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will have to take some time to read the statement carefully and figure out which function is getting called in which sequence, what are their effects. And, how the data is getting transformed in each steps.&lt;/p&gt;

&lt;p&gt;Fortunately, Elixir solves this problem elegantly by introducing a new operator called "Pipe" (&lt;code&gt;|&amp;gt;&lt;/code&gt;). It takes the result of the expression to its left/top and inserts it as the first parameter of the function invocation to its right/bottom. Using the pipe operator we can rewrite the above example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;ingredients&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;add_flavor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the steps &amp;amp; sequence of function calls are clear. We are passing the &lt;code&gt;ingredients&lt;/code&gt; to &lt;code&gt;mix()&lt;/code&gt;. The result of &lt;code&gt;mix()&lt;/code&gt; is getting piped to &lt;code&gt;add_flavor()&lt;/code&gt;. Then we &lt;code&gt;bake()&lt;/code&gt; the result and finally we &lt;code&gt;decorate()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Bottomline is, do not write Elixir codes with nested function calls use piping instead. It will make your code clear, concise and much more readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions &amp;amp; Pattern Matching
&lt;/h2&gt;

&lt;p&gt;Pattern Matching is one of the most powerful feature of Elixir Programming Language. Mastering pattern matching techniques will boost productivty and improve code quality. The key is to know when and where we can apply pattern matching. Let's explore the below python function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"head"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"tail"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"tail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"head"&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;return&lt;/span&gt; &lt;span class="s"&gt;"invalid"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function simply flips a coin. If the coin is &lt;code&gt;head&lt;/code&gt; it returns &lt;code&gt;tail&lt;/code&gt; and vice versa. It also returns &lt;code&gt;invalid&lt;/code&gt; for any other arguments. Now, if we want we can write it in a similar way in elixir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"head"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="s2"&gt;"tail"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"tail"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="s2"&gt;"head"&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="s2"&gt;"invalid"&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This sure works, but it doesn't look good. First of all, it has a nested &lt;code&gt;if...else&lt;/code&gt; block. Whenever you notice your code has nested blocks, take a few moment and think it thoroughtly. There must be a better way of doing it. In the above case, we do have a better way of achieving the same functionality. We can refactor this code with 3 simple lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"head"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"tail"&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;flip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"tail"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"head"&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;filp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"invalid"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks neat, isn't it? We are using pattern matching to match the argument directly from the function parameter. When the function &lt;code&gt;flip&lt;/code&gt; will be called, Elixir will take each method signature and match it with the input argument. As soon as the match occurs, it will execute the function and stop. So for example, if we call the &lt;code&gt;flip&lt;/code&gt; function with the parameter "tail". Elixir will first try to match the argument with the first function once, it fail it will move to the next one. Since, the second function takes "tail" as argument, it will get executed. We will get an output "head".&lt;/p&gt;

&lt;p&gt;It will also work for complex Data Structure such as Dictionary or Maps. For example, see the below function that takes a dictionary &lt;code&gt;person&lt;/code&gt; as argument and prints the full name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_fullname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"firstname"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"lastname"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dict &lt;code&gt;person&lt;/code&gt; has two key value pairs, &lt;code&gt;firstname&lt;/code&gt; and &lt;code&gt;lastname&lt;/code&gt;. We first retrieve the values from the dict and store them in two variables and later we print them by concatenating them using f-strings.&lt;/p&gt;

&lt;p&gt;In Elixir, we can do the pattern matching in the function signature like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_fullname&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;firstname:&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;lastname:&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;just like &lt;code&gt;dict&lt;/code&gt; Elixir has a data structure named Map which we are using for this example. The &lt;code&gt;firstname&lt;/code&gt; and &lt;code&gt;lastname&lt;/code&gt; are atoms, they are the key of the Map. The &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt; variable will get the value of the Map using pattern matching. And, in the function body we just return the concatenated string.&lt;/p&gt;

&lt;p&gt;The above examples are pretty basic but, they give us the glimpse of how pattern matching works. And, how it can help us to improve Elixir code.&lt;/p&gt;

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

&lt;p&gt;Before calling it a day, let's quickly recap what we've explored so far. We learned the key challenges of switching from different programming language to Elixir. We also explored some common mistakes and how to avoid them by taking advantage of Elixir features and best practices.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>programming</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Contribute to Lenra, a SaaS to create your crossplatform app, using any language</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Tue, 11 Oct 2022 14:15:27 +0000</pubDate>
      <link>https://dev.to/lenra/contribute-to-lenra-a-saas-to-create-your-crossplatform-app-using-any-language-22a6</link>
      <guid>https://dev.to/lenra/contribute-to-lenra-a-saas-to-create-your-crossplatform-app-using-any-language-22a6</guid>
      <description>&lt;p&gt;Hello !&lt;/p&gt;

&lt;p&gt;Check our website for more info &lt;a href="http://www.lenra.io"&gt;www.lenra.io&lt;/a&gt; about our project :)&lt;/p&gt;

&lt;p&gt;V / php / swift / java / C# / elixir / python .... We need contributors for our templates ! Feel free to help !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/template-v"&gt;https://github.com/lenra-io/template-v&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/template-php"&gt;https://github.com/lenra-io/template-php&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/template-swift"&gt;https://github.com/lenra-io/template-swift&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/template-java-springboot"&gt;https://github.com/lenra-io/template-java-springboot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/template-csharp"&gt;https://github.com/lenra-io/template-csharp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/template-elixir"&gt;https://github.com/lenra-io/template-elixir&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/template-python"&gt;https://github.com/lenra-io/template-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or if you're a NodeJS fan, you can help us with the migration of our data here :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/Lenra/issues/143"&gt;https://github.com/lenra-io/Lenra/issues/143&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy Hacking everyone !!&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>github</category>
      <category>python</category>
      <category>node</category>
    </item>
    <item>
      <title>Not so green Meta</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Tue, 11 Oct 2022 14:12:36 +0000</pubDate>
      <link>https://dev.to/lenra/not-so-green-meta-k70</link>
      <guid>https://dev.to/lenra/not-so-green-meta-k70</guid>
      <description>&lt;p&gt;Virtual worlds, a not so green Meta&lt;/p&gt;

&lt;p&gt;We hear a lot about the metaverse, but the concept is still unclear to the general public. The company Meta, ex-Facebook, has launched a campaign “Impact will be real” to educate on the subject. The commercial shows a surgeon training on a virtual mannequin and a history student projected in ancient Greece.&lt;/p&gt;

&lt;h2&gt;
  
  
  The promise of the metaverse
&lt;/h2&gt;

&lt;p&gt;With 3D, the metaverse facilitates the transmission of school and university knowledge, as well as the training of professionals. It allows creation of experiences without putting learners in dangerous situations, thanks to the projection in artificial environments.&lt;br&gt;
Advocates of the metaverse also point the positive impact on the carbon footprint, due to the elimination of unnecessary travel. Users can work without commuting or attend a conference on the other side of the world without traveling.&lt;br&gt;
For many, the metaverse is already shaping up the future of the Web. That alone is enough to justify the huge investments made by the Meta company, which wants to maintain a dominant position. Many other large companies are hoping in.&lt;br&gt;
However, can we say that the metaverse is really virtuous? To what extent is it compatible with the current issues of responsible digital technology?&lt;/p&gt;

&lt;h2&gt;
  
  
  The real environmental impact of the metaverse
&lt;/h2&gt;

&lt;p&gt;Today, the digital sector is responsible for 4% of global gas emissions. Servers, terminals, the use of rare minerals and the waste produced represent the other side of the coin.&lt;br&gt;
As for the metaverse, it requires much more computing power than today (we’re talking about an order of magnitude 1,000 times more). This means more and more data centers to transmit these very high definition images in real time.&lt;br&gt;
We must also take into account the renewal of equipment such as the purchase of virtual reality helmets and goggles, and more powerful computers, transferrring even more data on servers. The manufacture of these terminals requires the extraction, by a very toxic process, of rare minerals, mainly from China.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is at stake in Green IT ?
&lt;/h2&gt;

&lt;p&gt;The metaverse can be questioned with regard to the criteria of responsible digital technology, which concern accessibility, security, attention grabbing and digital sobriety.&lt;br&gt;
In terms of accessibility, it is obvious that the situation will worsen. Indeed, the metaverse is likely to further widen the inequality gap in terms of equipment power and connection speed.&lt;br&gt;
Security will probably also be put aside, under the pretext of offering the user an ever more fluid experience.&lt;br&gt;
As far as capturing attention through design processes is concerned, it is safe to say that the metaverse will only intensify the problem. Its immersive power already makes the user captive. The quest for time, money and user data pushes companies to deploy more and more ethically objectionable processes. The metaverse will increase the effect of dark patterns, elements designed to induce behavior contrary to the user’s interest.&lt;br&gt;
Finally, as far as digital sobriety is concerned, the aspects already mentioned concerning the cost of resources show that the gamble is not won.&lt;/p&gt;

&lt;p&gt;In summary, the metaverse seems to go against the grain of the Digital Responsibility movement. However, considering the urgency of the environmental situation, the idea of imposing sobriety values on the metaverse cannot be without hope.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vr</category>
      <category>greenit</category>
    </item>
    <item>
      <title>Hacktoberfest : contribute to Lenra, the app creation game-changing platform !!</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Mon, 03 Oct 2022 09:41:30 +0000</pubDate>
      <link>https://dev.to/lenra/hacktoberfest-contribute-to-lenra-the-app-creation-game-changing-platform--53dh</link>
      <guid>https://dev.to/lenra/hacktoberfest-contribute-to-lenra-the-app-creation-game-changing-platform--53dh</guid>
      <description>&lt;p&gt;Lenra is an open source framework to create your app using any language,  and deploy it without any Ops scale, built on ethical values.&lt;/p&gt;

&lt;p&gt;Check our website &lt;a href="http://www.lenra.io"&gt;www.lenra.io&lt;/a&gt; for more info !&lt;/p&gt;

&lt;p&gt;We are thrilled to share our project during HacktoberFest, and hope you'll find a way to contribute to any part of the platform you want. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data lover ?&lt;/strong&gt; With the migration of data management, from postgres to mongoDB, we have some changes to make in the application to be compatible here : &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/Lenra/issues/143"&gt;https://github.com/lenra-io/Lenra/issues/143&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rust fan&lt;/strong&gt; ? Create a dev interactive command in lenra_cli. The dev command builds  the app, starts it and displays the app logs when you run it. It's here : &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/Lenra/issues/144"&gt;https://github.com/lenra-io/Lenra/issues/144&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go, Python, Ruby, Elixir, V&lt;/strong&gt; ... As we create a platform usable in any langage, you can participate in developing any template here : &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/lenra-io/Lenra/issues/142"&gt;https://github.com/lenra-io/Lenra/issues/142&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you'll have fun !!&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>rust</category>
      <category>docker</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Here's our journey through data !</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Mon, 26 Sep 2022 12:28:37 +0000</pubDate>
      <link>https://dev.to/lenra/data-management-how-to-manage-data-properly--3353</link>
      <guid>https://dev.to/lenra/data-management-how-to-manage-data-properly--3353</guid>
      <description>&lt;h1&gt;
  
  
  How we manage data at Lenra
&lt;/h1&gt;

&lt;p&gt;Data management is a very important part for every application, even for Lenra. Today, I'm going to introduce you to our data management needs and how we solve them. But first, I will introduce you to the type of data we need to manage at Lenra.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.lenra.io"&gt;www.lenra.io&lt;/a&gt; is is made to accelerate the creation of your applications and simplify their hosting while preserving the personal data of your users.&lt;br&gt;
Lenra is built around the values of digital sobriety and data protection, meaning users of its tools anchor their practice in a more responsible and ethical digital world.&lt;/p&gt;

&lt;p&gt;Malware protection is a key point for our platform and has been respected through a process of improving the security of your data.&lt;/p&gt;

&lt;p&gt;The platform allows GDPR compliance and also the control by the user of his personal data.&lt;/p&gt;
&lt;h2&gt;
  
  
  Data ?
&lt;/h2&gt;

&lt;p&gt;A Lenra application is made of 2 components: widgets and listeners. The widgets are the graphical components, they are in JSON format and represent a description of the graphical interface. The listeners are the functions called in reaction to the user's actions on the graphical interface, such as pressing a button. All these components are described in a file called "manifest". It lists all the components that can be used within the application. In this part we will see the components as they were before the new data system was implemented. Schematically, here is how an application works&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--baTd7yR7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/45465504/191210399-c252aba0-5df9-42c6-9157-2cac46a424aa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--baTd7yR7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/45465504/191210399-c252aba0-5df9-42c6-9157-2cac46a424aa.png" alt="framework" width="880" height="324"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Widget
&lt;/h3&gt;

&lt;p&gt;Widgets are therefore the graphical components of an application, they describe the graphical interface in JSON format. A bit like HTML, the developer will be able to embed "lenra-components", a library made by Lenra. The "lenra-components" library is a set of flutter widgets reworked to fit the needs of the company.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(data, props) =&amp;gt; {
 return {
   "type": "text",
   "value": "Hello World!"
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As shown in this example we have a widget that is a function taking two parameters as input and returning some JSON corresponding to the interface. The two parameters are :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;data&lt;/strong&gt; : A JSON object representing the user data&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;props&lt;/strong&gt; : A JSON object allowing the developer to give properties to the widget&lt;/p&gt;

&lt;p&gt;This widget in JSON format will be validated and transformed into a Flutter widget using the JSON Schema. Once transformed, it will be displayed on the application. The widgets also have the possibility to be built according to the data, indeed the data of the application are passed to the widget so that it can use them in order to have a modular interface according to the data, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(data, props) =&amp;gt; {
 return {
   "type": "text",
   "value": data.text
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listeners
&lt;/h3&gt;

&lt;p&gt;The listeners are functions reacting to the user's actions and making modifications on the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(data, props, event) =&amp;gt; {
  return {
    text: "world"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As shown in the example, a listener is a function taking 3 parameters:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;data&lt;/strong&gt; : A JSON object containing the user's data.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;props&lt;/strong&gt; : A JSON object that allows to give properties to the listener.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;event&lt;/strong&gt; : A String that allows to specify to the listener the event that triggered its call.&lt;/p&gt;
&lt;h2&gt;
  
  
  What we need
&lt;/h2&gt;

&lt;p&gt;The system we have just seen is the system that was in place on Lenra. It was quite functional and quite easy to use but it could very quickly present some limits. Indeed on a small application like a "hello world" this system is quite sufficient, but on a larger application and storing different types of data, having only one data object can quickly become restrictive especially for data querying. A new system has therefore been designed.&lt;br&gt;
We had some specifications to respect for the new data system:&lt;/p&gt;

&lt;p&gt;We wanted to allow all developers to manage their data schema as they wish, a bit like Firebase does, we wanted a system that would abstract the entire data system behind the Lenra interface and allow developers to create their data easily through HTTP requests.&lt;/p&gt;

&lt;p&gt;We also wanted a system that is GDPR compliant by design, meaning that if the developer implements the obligatory listeners, he will have a GDPR compliant application by default. &lt;/p&gt;
&lt;h2&gt;
  
  
  What we do
&lt;/h2&gt;

&lt;p&gt;Following these needs, we have therefore imagined a data system that is close to an object-oriented database such as SQL for example. So we have two types of objects: &lt;strong&gt;Datastore&lt;/strong&gt; and &lt;strong&gt;Data&lt;/strong&gt;. A datastore can correspond to a SQL table and a data to an entry of this table. We thus have a Datastore containing data in JSON format which is a mix between a SQL system and a data format similar to NoSQL. In order to link data between them, we have added a DataReference object which allows to make a many_to_many relation between two Data.&lt;/p&gt;
&lt;h3&gt;
  
  
  Database schema
&lt;/h3&gt;

&lt;p&gt;Here is the database schema&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l85rnzIy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/45465504/192218350-91feab90-58af-4e88-981a-071beab1679b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l85rnzIy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/45465504/192218350-91feab90-58af-4e88-981a-071beab1679b.png" alt="Capture d’écran du 2022-09-26 09-24-36" width="880" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we find the tables of the three objects mentioned above, &lt;strong&gt;datastores&lt;/strong&gt;, &lt;strong&gt;datas&lt;/strong&gt; and &lt;strong&gt;data_references&lt;/strong&gt;, as well as the &lt;strong&gt;applications&lt;/strong&gt; and &lt;strong&gt;environments&lt;/strong&gt; tables mentioned in the previous point. The last table &lt;strong&gt;user_datas&lt;/strong&gt; allows us to identify to which user a data belongs, we will come back more precisely on how it works in the part which is reserved to it.&lt;/p&gt;
&lt;h3&gt;
  
  
  API
&lt;/h3&gt;

&lt;p&gt;Creation of an API that handles create/add/delete on our objects&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="s2"&gt;"/app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;LenraWeb&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;pipe_through&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;:api&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:ensure_auth_app&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DatastoreController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores/:_datastore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DatastoreController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:delete&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores/user/data/@me"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DataController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:get_me&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores/:_datastore/data/:_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DataController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:get&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores/:_datastore/data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DataController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:get_all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores/:_datastore/data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DataController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores/:_datastore/data/:_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DataController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:delete&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/datastores/:_datastore/data/:_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DataController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/query"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DataController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to know more about how our controllers work, you can find it at: &lt;a href="https://github.com/lenra-io/application-runner/tree/b4dac9754ae9a1925b5ab9a921ed5129bad7a624/lib/controllers"&gt;https://github.com/lenra-io/application-runner/tree/b4dac9754ae9a1925b5ab9a921ed5129bad7a624/lib/controllers&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Query system
&lt;/h3&gt;

&lt;p&gt;After implementing the new data system, we had to think of a way to query the data. The application data must be accessible from two different locations.&lt;br&gt;
First, we need to be able to retrieve and perform actions from the listeners. Indeed, listeners do not receive an object containing all the data of a user for an environment but must be able to request this data with an API call.&lt;br&gt;
Second, the data must be able to be queried from the widgets. As a reminder, widgets are written in JSON format, so we had to think about a JSON querying system. The listeners use this same format and will send a POST request on the /app/query route.&lt;/p&gt;
&lt;h4&gt;
  
  
  query format
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VALUE: (STRING, NUMBER, BOOLEAN, OBJECT, ARRAY),
QUERY: { ...MATCH_BODY: { ( ...PROPERTY_CHECK: { STRING: BOOLEAN_MATCHING_FUNCTION }, | ...PROPERTY_CHECK)+ }, },
FIND_FUNCTION: { $find: { ...MATCH_BODY, _datastore: STRING } },
MATCH_BODY: { ( ...PROPERTY_CHECK: { STRING: BOOLEAN_MATCHING_FUNCTION }, | ...PROPERTY_CHECK)+ },
PROPERTY_CHECK: { STRING: BOOLEAN_MATCHING_FUNCTION },
BOOLEAN_MATCHING_FUNCTION: ( MATCH_MATCHING_FUNCTION | EQ_MATCHING_FUNCTION | AND_MATCHING_FUNCTION | OR_MATCHING_FUNCTION | LT_MATCHING_FUNCTION | GT_MATCHING_FUNCTION | NOT_MATCHING_FUNCTION ),
BOOLEAN_MATCHING_FUNCTION_LIST: [ MATCH_BODY+ ]
EQ_MATCHING_FUNCTION: ( { $eq: VALUE } | VALUE ),
MATCH_MATCHING_FUNCTION:  { $match: MATCH_BODY },
AND_MATCHING_FUNCTION: { $and: BOOLEAN_MATCHING_FUNCTION_LIST },
OR_MATCHING_FUNCTION: { $or: BOOLEAN_MATCHING_FUNCTION_LIST },
NOT_MATCHING_FUNCTION: { $not: MATCH_BODY },
GT_MATCHING_FUNCTION: { $gt: NUMBER },
LT_MATCHING_FUNCTION: { $lt: NUMBER },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  query parser
&lt;/h4&gt;

&lt;p&gt;You can find our complete parser here: &lt;a href="https://github.com/lenra-io/query-parser/blob/2d3883e450826b35cfa09c1c80c24fc453dc1b71/lib/ast/parser.ex"&gt;https://github.com/lenra-io/query-parser/blob/2d3883e450826b35cfa09c1c80c24fc453dc1b71/lib/ast/parser.ex&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we have defined the format of the requests as seen before, we had to implement a parser that will easily transform this JSON into an Ecto request. To do so, we proceeded by steps, the first one being to transform the JSON into a format that can be easily processed by Elixir. To do this, we chose to make an AST tree, the AST tree corresponding to the requests follows this pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SQA5h35P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/45465504/192221423-62f8dbe8-a268-4afe-8c00-a57caa6b47de.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SQA5h35P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/45465504/192221423-62f8dbe8-a268-4afe-8c00-a57caa6b47de.png" alt="unnamed" width="880" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the pattern matching system provided by Elixir allows us to easily identify the patterns present in the JSON object in order to build step by step the ast tree with the corresponding object.&lt;br&gt;
Our parser is composed of two main functions &lt;strong&gt;parse_expr&lt;/strong&gt; and &lt;strong&gt;parse_fun&lt;/strong&gt;, here are the declinations of each function:&lt;/p&gt;

&lt;p&gt;In the case where we have a list as input, it is actually a $and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"$and"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A key that starts with $ is a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"$"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;parse_fun&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple k =&amp;gt; v clause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;left:&lt;/span&gt; &lt;span class="n"&gt;from_k&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
  &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there is a left in context, and is not a function, this is a simplified $eq function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defp parse_expr(value, %{left: _} = ctx) do
  parse_expr({"$eq", value}, ctx)
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final parse_expr create Value object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;ArrayValue&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;values:&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_bitstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;value:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;NumberValue&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;value:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parse function and with only one clause&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_fun&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"$and"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parse function and with many clauses&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_fun&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"$and"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;And&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;clauses:&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parse function eq&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;parse_fun&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;"$eq"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;left:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;left:&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;right:&lt;/span&gt; &lt;span class="n"&gt;parse_expr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the same system of pattern matching with parse the AST tree into Ecto query that can be executed by our server&lt;/p&gt;

&lt;h3&gt;
  
  
  The limit
&lt;/h3&gt;

&lt;p&gt;This system is functional and allows the developer to manage the data as he wants, only this system forces us to maintain a query system while Mongo already has a complete system.&lt;br&gt;
So we can ask ourselves why keep this system and not just switch to Mongo, at the moment, the only answer is that we can't keep the data_reference but the developer can make the reference he wants by putting the data id in another data.&lt;br&gt;
So we decided to rework the Postgres data management system to replace it with a system using Mongo.&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>security</category>
      <category>api</category>
    </item>
    <item>
      <title>Traefik middleware - Forward authentication</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Mon, 19 Sep 2022 13:38:28 +0000</pubDate>
      <link>https://dev.to/lenra/traefik-middleware-forward-authentication-1nc1</link>
      <guid>https://dev.to/lenra/traefik-middleware-forward-authentication-1nc1</guid>
      <description>&lt;p&gt;In this article we will explain how to use Traefik middlewares and routers to manage authentication to many applications on Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom authentication
&lt;/h2&gt;

&lt;p&gt;Custom auth delegates management to an external server.&lt;br&gt;
To manage custom authentication we will use the &lt;a href="https://doc.traefik.io/traefik/middlewares/http/forwardauth/#forwardauth"&gt;ForwardAuth Middleware&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this exemple, we will create a NodeJS Express server that persist authentication with a cookie containing a JWT token. &lt;/p&gt;

&lt;p&gt;For every request passing through the middleware it will check the JWT token.&lt;/p&gt;

&lt;p&gt;If it is not present or expired, it will send a login form to the client with a &lt;code&gt;401&lt;/code&gt; status code.&lt;/p&gt;

&lt;p&gt;We will use our previous secret &lt;code&gt;basic-auth-users-secret&lt;/code&gt; to manage the accounts.&lt;/p&gt;

&lt;p&gt;This is one kind of implementation, but you can imagine many authentication workflows.&lt;/p&gt;

&lt;p&gt;We will not explain how to dockerize the NodeJS server, but you can find many tutorials.&lt;/p&gt;
&lt;h3&gt;
  
  
  Implement the server
&lt;/h3&gt;

&lt;p&gt;The following environment variables need to be defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;COOKIE&lt;/code&gt;: the name of the cookie that will persists the JWT&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SECRET&lt;/code&gt;: The JWT secret to manage JWT&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;USERS_PATH&lt;/code&gt;: the path to the users file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VALIDITY&lt;/code&gt;: the authentication validity duration in seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example, the form values are sent in a HTTP header because the body of the request is not forwarded the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Router&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;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsonwebtoken&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;atob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;atob&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;htpasswd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;htpasswd-js&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;cookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COOKIE&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SECRET&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;usersPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;USERS_PATH&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;validity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VALIDITY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="c1"&gt;//in seconds&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;forwarded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Forwarded-Method&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Forwarded-Proto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Forwarded-Host&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Forwarded-Uri&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Forwarded-For&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;forwarded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&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;span class="nx"&gt;forwarded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;forwarded&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&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;roles&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Check JWT token&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&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;forwarded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Check login/password&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Form-Content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;let&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="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;loggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;htpasswd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticate&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;login&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="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;usersPath&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;loggedIn&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not logged in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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="s2"&gt;`Logged in &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="s2"&gt;. Redirect to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&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;span class="c1"&gt;// Create JWT token&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;validity&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;validity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;expire&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&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="na"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expire&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;expire&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// redirect to initial url&lt;/span&gt;
      &lt;span class="nx"&gt;res&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redirect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Redirect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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;er&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;er&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clearCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;js&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`function sendForm(e) {
    var form = e.currentTarget;
    var xhr = new XMLHttpRequest();
    var formData = new FormData(form);
    xhr.addEventListener('load', function(event) {
      window.location.reload();
    });
    xhr.addEventListener('error', function(event) {
      alert('Oups! Something went wrong.');
    });
    xhr.open('POST', '');
    xhr.setRequestHeader('Form-Content', btoa(form.login.value+':'+form.password.value));
    xhr.send(formData);

    e.preventDefault();
    e.stopPropagation();
    return false;
  }`&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the &lt;code&gt;index&lt;/code&gt; view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block content
  h1= "Login"
  form(method="post", onsubmit="return sendForm(event);")
    input(name="login")
    input(name="password", type="password")
    input(name="redirect", type="hidden", value= url)
    button= "Login"
  script= js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the &lt;code&gt;redirect&lt;/code&gt; view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block content
  h1= "Redirection en cours"
  script= `window.location = "${url}";`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy the authentication middleware
&lt;/h3&gt;

&lt;p&gt;First we will define a Secret containing the needed environment variables:&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;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;Secret&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;custom-auth-secret&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# The cookie name&lt;/span&gt;
  &lt;span class="na"&gt;COOKIE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-cookie-name&lt;/span&gt;
  &lt;span class="c1"&gt;# The JWT &lt;/span&gt;
  &lt;span class="na"&gt;SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The jwt secret key&lt;/span&gt;
  &lt;span class="c1"&gt;# The JWT and cookie validity in seconds&lt;/span&gt;
  &lt;span class="na"&gt;VALIDITY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1800"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's define the server Deployment and Service:&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;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&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;apps/v1&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;custom-auth&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom-auth&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;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom-auth&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;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;custom-auth&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom-auth&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom-auth&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;custom-auth-server:latest&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&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;USERS_PATH&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/auth/users&lt;/span&gt;
          &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&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;custom-auth-secret&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&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;users&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/auth"&lt;/span&gt;
              &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&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;users&lt;/span&gt;
        &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;basic-auth-users-secret&lt;/span&gt;
&lt;span class="nn"&gt;---&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&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;custom-auth&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom-auth&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;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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&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;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;k8s-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;custom-auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we define the Traefik ForwardAuth Middleware in the same namespace of the server:&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;traefik.containo.us/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;Middleware&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;custom-auth&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;forwardAuth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://auth.traefik:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can now be used in Traefik routers:&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;traefik.containo.us/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;IngressRoute&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;test-custom-auth&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;entryPoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
  &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&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;Rule&lt;/span&gt;
      &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Host(`test-custom-auth.lenra.io`)&lt;/span&gt;
      &lt;span class="na"&gt;middlewares&lt;/span&gt;&lt;span class="pi"&gt;:&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;test-custom-auth&lt;/span&gt;
          &lt;span class="c1"&gt;# Define the middleware namespace if you use is it another one&lt;/span&gt;
          &lt;span class="c1"&gt;# namespace: my-namespace&lt;/span&gt;
      &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&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;my-service&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;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Go further
&lt;/h2&gt;

&lt;p&gt;We can imagine many things to improve this authentication system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pass the allowed users to the custom authentication server by defining it in the middleware address field&lt;/li&gt;
&lt;li&gt;define the authentication cookie at the main domain in order to login only once&lt;/li&gt;
&lt;li&gt;manage authentication with a third-part OAuth provider, like Github&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Traefik middleware - Basic authentication</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Wed, 07 Sep 2022 13:38:50 +0000</pubDate>
      <link>https://dev.to/lenra/traefik-middleware-basic-authentication-4147</link>
      <guid>https://dev.to/lenra/traefik-middleware-basic-authentication-4147</guid>
      <description>&lt;p&gt;In this article we will explain how to use Traefik middlewares and routers to manage authentication to many applications on Kubernetes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Traefik authentication middleware&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic Authentication&lt;/li&gt;
&lt;li&gt;Deploy the authentication middleware&lt;/li&gt;
&lt;li&gt;Go further&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic Authentication
&lt;/h2&gt;

&lt;p&gt;Basic auth is a good way to restrict access to users you choose. &lt;/p&gt;

&lt;p&gt;To manage &lt;strong&gt;Basic Authentication&lt;/strong&gt; with Traefik, we will use the &lt;a href="https://doc.traefik.io/traefik/middlewares/http/basicauth/#basicauth"&gt;BasicAuth Middleware&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, you need to define a secret with the Basic Authentication users at the format &lt;code&gt;name:hashed-password&lt;/code&gt; with password hashed using &lt;strong&gt;MD5&lt;/strong&gt;, &lt;strong&gt;SHA1&lt;/strong&gt;, or &lt;strong&gt;BCrypt&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can hash passwords using the following command: 'htpasswd -nb user password'.&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;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;Secret&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;basic-auth-users-secret&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;user1:$apr1$rKM7TQZQ$FUFmIklAwWBy80pHFcZlM0&lt;/span&gt;
    &lt;span class="s"&gt;user2:$apr1$elAEjLXh$l5NtPMsZ5YmZhjKPJ5u4r/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the middleware instance:&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;traefik.containo.us/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;Middleware&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;test-basic-auth&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;basicAuth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;basic-auth-users-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now use the middleware in Traefik routers:&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;traefik.containo.us/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;IngressRoute&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;test-basic-auth&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;entryPoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
  &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&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;Rule&lt;/span&gt;
      &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Host(`test-basic-auth.lenra.io`)&lt;/span&gt;
      &lt;span class="na"&gt;middlewares&lt;/span&gt;&lt;span class="pi"&gt;:&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;test-basic-auth&lt;/span&gt;
      &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&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;my-service&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;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stay tuned, we will see soon how to set up the forward authentication middleware !&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>javascript</category>
      <category>node</category>
      <category>devops</category>
    </item>
    <item>
      <title>Introducing Dofigen !</title>
      <dc:creator>Alienor </dc:creator>
      <pubDate>Tue, 16 Aug 2022 16:52:00 +0000</pubDate>
      <link>https://dev.to/lenra/introducing-dofigen--nbi</link>
      <guid>https://dev.to/lenra/introducing-dofigen--nbi</guid>
      <description>&lt;p&gt;Glad to share with you our very first rust project, Dofigen !&lt;br&gt;
It's a simple tool that generates dockerfiles from YAML (or JSON) structure. &lt;br&gt;
&lt;a href="https://github.com/lenra-io/dofigen"&gt;Available on Github here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it's opensource !! Enjoy !&lt;/p&gt;

</description>
      <category>programming</category>
      <category>docker</category>
      <category>rust</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
