<?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: Shubhojyoti</title>
    <description>The latest articles on DEV Community by Shubhojyoti (@shubho).</description>
    <link>https://dev.to/shubho</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178401%2Fcf59e803-8040-4d30-8e5b-7084b76f2f2d.jpg</url>
      <title>DEV Community: Shubhojyoti</title>
      <link>https://dev.to/shubho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shubho"/>
    <language>en</language>
    <item>
      <title>How I created my Gatsby blog with WordPress as the backend</title>
      <dc:creator>Shubhojyoti</dc:creator>
      <pubDate>Fri, 02 Aug 2019 19:37:31 +0000</pubDate>
      <link>https://dev.to/shubho/how-i-created-my-gatsby-blog-with-wordpress-as-the-backend-6d4</link>
      <guid>https://dev.to/shubho/how-i-created-my-gatsby-blog-with-wordpress-as-the-backend-6d4</guid>
      <description>&lt;p&gt;Recently, I created my blog again after junking my writings on my other domains. My previous experience with Static Site Generators (SSG) was Hugo. This time I used Gatsby as my primary work deals with JavaScript, so it was a quick development process for me. For the backend, I used WordPress.&lt;/p&gt;

&lt;p&gt;I plan to write a multi-post series as I have lots of notes on how I went about it. There are still some CSS polishing required. But overall, the site is ready. This part has loads of rambling, so feel free to skip it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do I use SSGs? - A history.
&lt;/h2&gt;

&lt;p&gt;I don’t know about you, but I love static sites. There are no headaches involved. Just plain HTML and CSS with a dash of JavaScript if required. That is how I learnt about developing websites. It was later that I realised maintaining them is a headache. A single change in the theme required changing and keeping track of all the files. It was 2005 when I discovered WordPress. I was going to start college during the summer, and I wanted to use something for my journal. I stuck with WordPress for the next 8-10 years. My main issue was it was slow even though my blog received barely any traffic. I used the recommended caching plugins, which improved it. But it was always an extra step.&lt;/p&gt;

&lt;p&gt;Then I found Hugo. I moved my [Enjoyable Recipes] blog in 2017. It was a mess. I learned Go language, even though it was not required. The build was super fast, and I loved the speed with which the site loaded. However, there were multiple breaking changes in later versions. Shifting mentally from JavaScript development at work to Golang was too much for me at that time. So during the current redesign, I considered a JavaScript-based SSG. I studied Gatsby and Eleventy. Ultimately I decided on Gatsby because I was working on two React projects at that time so this was a natural fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Backend CMS
&lt;/h2&gt;

&lt;p&gt;I started with markdown files, moved to Contentful, finally settling on WordPress. I love writing in markdown. My Hugo blog is entirely in markdown as there is no other option. For the current site, I had the following requirements. These are solely my requirements. YMMV.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Markdown Support&lt;/strong&gt; - Contentful has native Markdown support. WordPress requires a plugin. Advantage Contentful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image Management&lt;/strong&gt; - I didn’t want to check-in images to my repository. Also, I wanted automatic resizing wherever necessary. Netlify has support via Large Media. But I did not want to add LFS support. In case I decide to leave Netlify, I wanted the images resized with me. I considered Cloudinary too who have a generous free plan. But I did not want to add another provider. Contentful has automatic image management, which is fantastic. WordPress has Media Management and image resizing options via the plugin system. Advantage WordPress and Contentful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata for Images&lt;/strong&gt; - Advanced Custom Fields (ACF) plugin for WordPress quickly add custom fields, and metadata support to posts, pages and images. Contentful only allows adding title, description and alt text. We need to create a separate content type for images and add extra fields. Advantage WordPress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Categorization&lt;/strong&gt; - Contentful supports categories and tags but in a round-about way. Everything needs to have a separate content type. WordPress has in-built support. Just type and press enter. Advantage WordPress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post Series Support&lt;/strong&gt; - This is slightly difficult in Contentful and easier in WordPress. In Contentful, you can create references to other posts and then can link them in HTML. WordPress too does not support this natively. But it is easier (for me) using custom taxonomies. Tie between WordPress and Contentful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Considering the above requirements, WordPress was a better fit for me. However, I loved Contentful. Its interface is a beauty. Their free plan, their image support and no need to manage installations make it an excellent CMS. I also considered Ghost. But they have no image resize support yet, so it was out.&lt;/p&gt;

&lt;p&gt;Finally, I write my posts in markdown.  I manage these in a private repository so that I never lose them if my WordPress installation gets corrupted.&lt;/p&gt;

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

&lt;p&gt;I know that was loads of rambling. In the next part, I will write about my WordPress setup and finally begin the finale - Gatsby integration. What do you use for your website?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.shubho.dev/coding/how-i-created-my-gatsbyjs-blog-with-wordpress-as-the-backend/" rel="noopener noreferrer"&gt;Shubho.Dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>wordpress</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How I use JavaScript Promises</title>
      <dc:creator>Shubhojyoti</dc:creator>
      <pubDate>Thu, 25 Jul 2019 17:38:24 +0000</pubDate>
      <link>https://dev.to/shubho/how-i-use-javascript-promises-19c6</link>
      <guid>https://dev.to/shubho/how-i-use-javascript-promises-19c6</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.shubho.dev/coding/how-i-use-javascript-promises/" rel="noopener noreferrer"&gt;Shubho.Dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Async programming in JavaScript was scary for me. The only async paradigm I was comfortable with was jQuery's &lt;code&gt;$.ajax&lt;/code&gt;. However, I went full vanilla JavaScript for the past 8 years, and when I started working with NodeJS, I had to learn Promises. I haven't dabbled much with third-party libraries like Bluebird. I have the most experience with native Promise.&lt;/p&gt;

&lt;p&gt;My main issue with &lt;code&gt;Promise&lt;/code&gt; (or asynchronous paradigm in general) used to be when I wanted to execute statements after the Promise statement began. It took some time to realise that once a Promise statement fires, there is no way to cancel it. Another issue was Promise chaining. This one was a kicker. My earlier functions with Promises always looked like friends of callback hell. After all these years and working on a couple of big projects, I can safely say I love Promises. Even though async/await is the new fad, I still love Promises.&lt;/p&gt;

&lt;p&gt;So here is how I use Promises to make my coding life simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Promise skeleton
&lt;/h2&gt;

&lt;p&gt;Whenever I create a new function that returns a Promise, I create the skeleton first. Since the function cannot return anything other than Promise based values, I always wrap all the statements of the function within the Promise.&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;function&lt;/span&gt; &lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// The function body&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above sample function wraps its entire statement within the Promise, returning immediately. You can either &lt;code&gt;resolve()&lt;/code&gt; or &lt;code&gt;reject()&lt;/code&gt; the output you want from the body. This way, I never make a mistake of not returning a Promise. It also helps me in creating Promise chains. Whenever in a chain, I realise I need a new function, I create the skeleton name it appropriately and finish the main chain. Then I come back one by one and finish the individual functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promise chains - Points to remember
&lt;/h2&gt;

&lt;p&gt;Promise chaining is tricky. If we are not careful, we can have a new type of callback hell. An example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;promiseCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;aNewFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;someOtherFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;someOtherValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// Do something&lt;/span&gt;
                        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someOtherValue&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;err1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// Error in inner function&lt;/span&gt;
                        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Error in outer function&lt;/span&gt;
                &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above sample &lt;code&gt;aFunction()&lt;/code&gt; and &lt;code&gt;someOtherFunction()&lt;/code&gt; are two functions returning Promises. If you see carefully, the sequence looks like a callback hell. The inner then and catch the chain, and outer ones are independent. We cannot handle errors in a common catch block, and we need to be careful that the inner functions are always the last line within their outer &lt;code&gt;then()&lt;/code&gt; otherwise we can't control the execution flow.&lt;/p&gt;

&lt;p&gt;A better way with chains:&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;function&lt;/span&gt; &lt;span class="nf"&gt;promiseCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;aNewFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;someOtherFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;someOtherValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Do something&lt;/span&gt;
                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someOtherValue&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Error in outer function&lt;/span&gt;
                &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns within the &lt;code&gt;then&lt;/code&gt; chain can only have three types:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Promise&lt;/strong&gt; - A &lt;code&gt;then&lt;/code&gt; function in a chain can return a Promise. It's result is passed to the next &lt;code&gt;then&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalar Value&lt;/strong&gt; - A &lt;code&gt;then&lt;/code&gt; function in a chain can return a  value like a String or a Number. This value is passed to the next &lt;code&gt;then&lt;/code&gt; as is and the chain can continue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throw&lt;/strong&gt; - A &lt;code&gt;then&lt;/code&gt; function can &lt;code&gt;throw&lt;/code&gt; an error, which moves the execution to the catch block.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As long as all your returns within a &lt;code&gt;then&lt;/code&gt; follow the above three types, you shouldn't have issues following your Promise chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
Remember to always &lt;code&gt;resolve()&lt;/code&gt; or &lt;code&gt;reject()&lt;/code&gt; in the last &lt;code&gt;then&lt;/code&gt; or &lt;code&gt;catch&lt;/code&gt; of the chain.&lt;/p&gt;
&lt;h2&gt;
  
  
  When to create a new Promise function
&lt;/h2&gt;

&lt;p&gt;Within a Promise chain, if there are multiple if-else conditions, and each condition can lead to different Promise results, it is an excellent time to create a new function that returns a Promise. This way, the Promise chain returns a single statement calling the new function.&lt;/p&gt;
&lt;h2&gt;
  
  
  Handling a scalar value or a Promise function in one step
&lt;/h2&gt;

&lt;p&gt;Assume we have a function which gets the marks attained by a student using his roll number. However, the function either takes a roll number as an input or the name of the student. The marks can be attained from the DB only using the roll number. Here is some pseudo-code.&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;function&lt;/span&gt; &lt;span class="nf"&gt;getMarks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&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;rollNumberPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rollNumber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;rollNumberPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rollNumber&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;studentName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;rollNumberPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRollNumberFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;studentName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;rollNumberPromise&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nothing worked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;rollNumberPromise&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rollNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;get_marks_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rollNumber&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;marks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marks&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getRollNumberFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;studentName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;fn_to_get_roll_number_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;studentName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rollNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rollNumber&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fn_to_get_roll_number_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;studentName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// some code&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;get_marks_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rollNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// some code&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;getMarks(obj)&lt;/code&gt; takes an Object as an input. We create a local variable &lt;code&gt;rollNumberPromise&lt;/code&gt;. If the rollNumber is already present, we save the value in the variable using &lt;code&gt;Promise.resolve()&lt;/code&gt;. This creates a Promise which resolves when called with the value. If student’s name is sent, then we save the call to the function &lt;code&gt;getRollNumberFromName(studentName)&lt;/code&gt; to the local variable. Calling &lt;code&gt;rollNumberPromise.then()&lt;/code&gt; returns a rollNumber whether it is received from the DB or sent directly as input to the function. Using it this way ensures that &lt;code&gt;getMarks()&lt;/code&gt; has a single Promise chain, rather than an if-else condition based on whether the input passed was a number or a name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invoke a Promise at the end
&lt;/h2&gt;

&lt;p&gt;As mentioned before, once a Promise, once invoked, cannot be cancelled. Any statements which do not depend on the Promise output and which can be carried out independently without an async call should complete before you start a Promise chain in your function. Once a Promise chain begins, any subsequent steps must be within the &lt;code&gt;then&lt;/code&gt; chain. The only exception to this is when you do not care of the Promise value, and you want the Promise to execute in the background while your primary function keeps running.&lt;/p&gt;

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

&lt;p&gt;Promises are difficult. However, with practice and following some rules, it makes working with them a charm. I strictly follow the above rules, and I never go wrong with Promises these days. Find out what you are comfortable with and create your own rules.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Wordpress HTML to Markdown for Gatsby</title>
      <dc:creator>Shubhojyoti</dc:creator>
      <pubDate>Mon, 22 Jul 2019 16:34:37 +0000</pubDate>
      <link>https://dev.to/shubho/wordpress-html-to-markdown-for-gatsby-3afl</link>
      <guid>https://dev.to/shubho/wordpress-html-to-markdown-for-gatsby-3afl</guid>
      <description>&lt;p&gt;I am currently in the process of creating my blog using WordPress as the backend and Gatsby for the frontend. One of the most enticing features of Gatsby is plugins. Almost every feature you might want on your blog is available as a plugin, or you can create one for yourself. As a developer who has dabbled with WordPress plugins (but is not proficient in PHP) and knows JavaScript, I feel creating plugins for Gatsby is way easier. Of course, that is a biased opinion coming from me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gatsby source plugin for WordPress
&lt;/h2&gt;

&lt;p&gt;Gatsby has many official plugins. Their structure is similar, but Gatsby does provide some standard terminology to make it easy to recognize the purpose for it. &lt;a href="https://www.gatsbyjs.org/docs/naming-a-plugin/" rel="noopener noreferrer"&gt;https://www.gatsbyjs.org/docs/naming-a-plugin/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Initially, I decided to use Contentful for my backend, the plugin being &lt;code&gt;gatsby-source-contentful&lt;/code&gt; (see how naming it following the standard convention helps). The Contentful plugin provides all the posts as a Markdown node in GraphQL, and as a result, all “transformation” plugins for “Remark” can be used on them. Now the transformation plugins for “Remark” for “transforming” markdown data are fantastic. And working on the Contentful data using them is a pleasure.&lt;/p&gt;

&lt;p&gt;For getting data from WordPress into Gatsby, we use a “source” plugin &lt;code&gt;gatsby-source-wordpress&lt;/code&gt;. I will discuss my reason for using WordPress in another post. But the main issue I faced with this plugin was it queries the data from the WordPress REST API and then creates the GraphQL schema for use within Gatsby. But the WordPress REST API by default returns the content only as HTML. So even if you write your posts as Markdown using some WordPress plugin (I use [WP Githuber MD]), the REST API will return the final content. However, this makes sense for WordPress as the output for their themes are always HTML. But I needed Markdown as I wanted to use those transformer plugins and they only work on the Markdown nodes. There are multiple Github issues on them like here &lt;a href="https://github.com/gatsbyjs/gatsby/issues/6799" rel="noopener noreferrer"&gt;https://github.com/gatsbyjs/gatsby/issues/6799&lt;/a&gt;. Even if a WordPress Markdown plugin exposes a separate REST endpoint, the Gatsby source plugin needed to support these. I didn’t want to find such a plugin or hack the official source plugin for Gatsby. 😀&lt;/p&gt;

&lt;h2&gt;
  
  
  Turndown - Convert HTML to Markdown
&lt;/h2&gt;

&lt;p&gt;So I wanted to look for a solution which can convert HTML to Markdown. Since I am always a DIY guy, I started reading on ASTs and started writing a conversion from HTML to Markdown by myself. I spent three days and had a working version. But there were lots of bugs. I realized this was silly of me. There must be some package already. Enter [Turndown]. It was awesome. The conversion was almost perfect. So I junked my conversion library and instead went to write a local Gatsby plugin that takes a WordPress Post (or Page) node and creates a Markdown node out of it using Turndown.&lt;/p&gt;

&lt;h2&gt;
  
  
  The plugin &lt;code&gt;gatsby-transformer-wordpress-markdown&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;I named the plugin as per the Gatsby naming standards. The folder “gatsby-trasformer-wordpress-markdown” goes under the plugins folder of your root Gatsby project.&lt;/p&gt;

&lt;p&gt;The folder has 3 files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── gatsby-node.js
├── index.js
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt; only contains a line &lt;code&gt;// noop &lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt; contains the name of the plugin and the &lt;code&gt;turndown&lt;/code&gt; package as a dependency &lt;code&gt;yarn add turndown&lt;/code&gt; and &lt;code&gt;yarn add turndown-plugin-gfm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main workhorse is the &lt;code&gt;gatsby-node.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In my main &lt;code&gt;gatsby-config.js&lt;/code&gt;, I call the plugin as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;siteMetadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-transformer-remark`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;plugins&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="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-remark-reading-time`&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-remark-embed-gist`&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="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-remark-prismjs`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="na"&gt;classPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;aliases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="na"&gt;javascript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                            &lt;span class="p"&gt;},&lt;/span&gt;
                            &lt;span class="na"&gt;inlineCodeMarker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;showLineNumbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;noInlineHighlight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="na"&gt;showLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                        &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-transformer-wordpress-markdown`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;turndownPlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;turndown-plugin-gfm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I haven’t added any tests as such as this is my local plugin. I might need to clean it up a bit. But here are a couple of points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The plugin needs to tie in during the &lt;code&gt;onCreateNode&lt;/code&gt; lifecycle of Gatsby build. In the current case, during the creation of a WordPress Post or Page node, the above plugin executes.&lt;/li&gt;
&lt;li&gt;Turndown, by itself has a plugin system. I am using the &lt;code&gt;turndown-plugin-gfm&lt;/code&gt; plugin. The plugin enables GitHub specific markdowns like tables in the Markdown Output. Line nos 26-35 are options you can pass to the local plugin. I am using all the defaults from the main &lt;code&gt;turndown&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;For each WordPress Post and Page node created, the plugin extracts the HTML &lt;code&gt;content&lt;/code&gt;, runs &lt;code&gt;TurndownService&lt;/code&gt; against it and creates a Markdown child node of type &lt;code&gt;MarkdownWordpress&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Since a new node of mediaType &lt;code&gt;text/markdown&lt;/code&gt; is created, the &lt;code&gt;gatsby-transformer-remark&lt;/code&gt; and its sub-plugins are run over them.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;In pure markdown nodes, the Markdown content is as you have written. However, note that in this case, WordPress has already created a HTML out of your post, and you are converting it back to Markdown. So if you use any special Markdown syntax, they will be lost. I did work around some of them as they were specific to my use case (I will write more on these in a future post), but YMMV.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>wordpress</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Add a no-js class in Gatsby</title>
      <dc:creator>Shubhojyoti</dc:creator>
      <pubDate>Tue, 16 Jul 2019 20:55:18 +0000</pubDate>
      <link>https://dev.to/shubho/add-a-no-js-class-in-gatsby-2914</link>
      <guid>https://dev.to/shubho/add-a-no-js-class-in-gatsby-2914</guid>
      <description>&lt;p&gt;I have been working with GatsbyJS for the past week. I am trying to set up my new blog. My old blog used to be on WordPress. But after working with Hugo for my recipe blog, I fell in love with static site generators. I learnt HTML/CSS using static HTML sites. My first website contained folders of HTML pages. I loved that approach. However, I outgrew it when I started journaling. Copying the HTML template every time and then replace the latest writing was a pain. When I wanted a design refresh (which was often), it was painful. And that is how I discovered WordPress.&lt;/p&gt;

&lt;p&gt;My initial foray with Static Site Generators (SSG) was Hugo. It had a steep learning curve for me, especially since I didn’t know template syntax in Golang. But I credit Hugo for spiking my interest in Golang, and I studied the language due to it (though you do not need to know Go to learn using Hugo).&lt;/p&gt;

&lt;p&gt;However, the language I am most comfortable in is JavaScript. I was late to the React game (Angular is my first love). I started using it two months back. Once I got comfortable enough to code in React, I wanted to create my blog in Gatsby - static site, JavaScript, and React. I love it.&lt;/p&gt;

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

&lt;p&gt;Add a “no-js” class to the document head in a Gatsby site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do it?
&lt;/h2&gt;

&lt;p&gt;I have this terrible habit of checking websites by disabling JavaScript. Not because I want to find issues with the site but mostly to find the fresh ways people make their site. Some sites create wonderful fallbacks for their site, and it’s great to see the way they enhance the experience with JavaScript. And others make fantastic and stunning websites without JavaScript. With my Gatsby site, I wanted to see how my site will behave by disabling JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; - Do not disable JavaScript from your Developer Tools. That will not be an actual test of the site behavior as the service workers are still loaded. To altogether disable JavaScript, do it from the browser settings.&lt;/p&gt;

&lt;p&gt;So I disable JavaScript and fire up my Gatsby site &lt;code&gt;gatsby build; gatsby serve&lt;/code&gt;. Everything looks good. It does display that “This app works best with JavaScript” that Gatsby automatically adds. But other than that, all is well. However, some JavaScript-only functionality will not work. e.g., I had a theme switcher. It works with CSS Variables, but the actual switching and remembering of the old settings are JavaScript. So the switcher is there, but the user clicks on it, and nothing happens. Wouldn’t it be nice if all JavaScript functionality doesn’t even show up? Many sites handle this by adding a &lt;code&gt;no-js&lt;/code&gt; class to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues galore
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;no-js&lt;/code&gt; class is added to the HTML by default. JavaScript is used to replace it. The JS code is the following three liner.&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&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="p"&gt;{&lt;/span&gt;  
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;js&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;I am using the react-helmet library to manage the header. Using the &lt;code&gt;htmlAttributes&lt;/code&gt; property of &lt;code&gt;&amp;lt;Helmet&amp;gt;&lt;/code&gt; I am already managing the &lt;code&gt;class&lt;/code&gt; property. So I added the &lt;code&gt;no-js&lt;/code&gt; class there. And I put the above JS code in a separate JS file, and I call it in &lt;code&gt;gatsby-browser.js&lt;/code&gt; file. Does it work? No. Even though my JS file is sourced, react-helmet is dynamic. It fires and keeps the header updated even when I am replacing it from my static HTML. And worse, the &lt;code&gt;no-js&lt;/code&gt; class remains every time so all my JavaScript-only behavior is gone even when it is enabled. So I cannot club &lt;code&gt;no-js&lt;/code&gt; class to react-helmet as I am already managing it there.&lt;/li&gt;
&lt;li&gt;I put the &lt;code&gt;no-js&lt;/code&gt; as a body class. But, you guessed it, I am managing the body classes too using react-helmet. So that’s a no go.&lt;/li&gt;
&lt;li&gt;As mentioned here [Customize Gatsby HTML] I copy over the html.js. I inlined the script in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag and manually add the class to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. Doesn’t work as react-helmet removes the class. 😢&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;So finally I figured it out. Since I want to continue using react-helmet to manage my &lt;code&gt;head&lt;/code&gt; classes, I needed some other property to hold this value. So I add a &lt;code&gt;data-html-class="no-js"&lt;/code&gt; to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; in &lt;code&gt;html.js&lt;/code&gt; file. And then I inline the script, but instead of replacing class, I do a &lt;code&gt;setAttribute&lt;/code&gt;. Here is how the template looks (only showing the HTML template) from &lt;code&gt;html.js&lt;/code&gt;. The relevant parts are line number 3 and line numbers 21-28.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;htmlAttributes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="nx"&gt;charSet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="nx"&gt;httpEquiv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-ua-compatible&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ie=edge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;viewport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width=device-width, initial-scale=1, shrink-to-fit=no&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headComponents&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bodyAttributes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preBodyComponents&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
          &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`body`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;___gatsby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postBodyComponents&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
            &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
            window.addEventListener('DOMContentLoaded', function() {
                document.querySelector('html').setAttribute('data-body-class', 'js')
            });
            `&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now in CSS, I can have this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-body-class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'no-js'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.only-js&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Whichever elements are JavaScript-only, I add the class &lt;code&gt;only-js&lt;/code&gt; to them, and their display property is set to &lt;code&gt;none&lt;/code&gt; when JavaScript is disabled.&lt;/p&gt;

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

&lt;p&gt;HTML is awesome. JavaScript is awesome. Gatsby is awesome. I am in love.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>beginners</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Elastic Search Update by Query with Ingest Pipeline</title>
      <dc:creator>Shubhojyoti</dc:creator>
      <pubDate>Sun, 14 Jul 2019 22:22:49 +0000</pubDate>
      <link>https://dev.to/shubho/elastic-search-update-by-query-with-ingest-pipeline-2k16</link>
      <guid>https://dev.to/shubho/elastic-search-update-by-query-with-ingest-pipeline-2k16</guid>
      <description>&lt;p&gt;I should start with a confession. I love Elasticsearch. It feels fantastic to feed it any document and then search even the precise terms out of it. However, when I started creating and managing a cluster at work, it was a nightmare. I was a beginner, so lots of concepts took time to sink in. Most of the tutorials I found online were of version 1.x-2.x but ES was already at 5.x and just about started the 6.x line. The initial cluster was created on 2.x version and to upgrade it to latest 6.x line required an upgrade first to 5.x line and then finally to the 6.x line.&lt;/p&gt;

&lt;p&gt;Since it was still just 1 month into the data feeding the data was not that huge, and the upgrades took 2-3 days (due to the reindexing involved). Our cluster is both index and query heavy. However, indexing is on a best-effort basis. The entire pipeline allows the system to index at various times four to five times. So as I was reindexing and upgrading my cluster, new data was still coming in the old cluster. Once the reindexing completed, I did another reindexing with only the new data. Also, any further data during this reindex was just thrown off. Because each indexing pipeline has around 5 tries at various intervals, eventually the dropped data came back into the new system.&lt;/p&gt;

&lt;p&gt;The above process is easy when the overall data load in the cluster is less. Currently, our cluster now has around 15TB worth of data spanning a year, and it supports 3 different systems. Reindexing these days is out of the question. Most of the indices are hot and continuously being used.&lt;/p&gt;

&lt;p&gt;Recently I had a requirement of updating a field of a couple of indices with a different value. Now the good thing was it didn’t need a change in the mapping. The field type did not change. It was just the data that needed to be updated. &lt;/p&gt;

&lt;p&gt;As an example, assume the field name to be “jobIdentifier”. Most of the documents had this value as alphanumeric. However, some of the documents had entries like “213452-2-12932-&amp;lt;Alphanumberic&amp;gt;”. The requirement was to normalize these values to just &amp;lt;Alphanumberic&amp;gt;. Simple enough, right? &lt;/p&gt;

&lt;h2&gt;
  
  
  Updating Elasticsearch field value using regular expressions
&lt;/h2&gt;

&lt;p&gt;The straightforward way to do this is regular expressions using Painless scripting language. From Elasticsearch docs,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Painless is a simple, secure scripting language designed specifically for use with Elasticsearch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using Painless scripting language for the above requirement, we can write the regular expression like this.&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;"script"&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;"lang"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"painless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ctx._source.jobIdentifier = /[0-9]+-[0-9]+-[0-9]+-(.*)/.matcher(ctx._source.jobIdentifier).replaceAll('$1')"&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;So in the regular expression, it matches field “jobIdentifier” with the value of type &lt;code&gt;[0-9]+-[0-9]+-[0-9]+-(.*)&lt;/code&gt; and replaces it with the grouped pattern &lt;code&gt;.*&lt;/code&gt;. Thereby removing the preceding 3 numbers along with the hyphen separator.  So a value like &lt;code&gt;213452-2-12932-Some_random_value&lt;/code&gt; becomes &lt;code&gt;Some_random_value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, due to StackOverflow issues in Java, regular expressions in Painless scripting are disabled by default in the latest versions of Elasticsearch. [&lt;a href="https://github.com/elastic/elasticsearch/pull/20427" rel="noopener noreferrer"&gt;https://github.com/elastic/elasticsearch/pull/20427&lt;/a&gt;] The issue and its related links describe the fix in great detail. It convinced me to look into other solutions to the above issue. I didn’t want to enable regular expressions in scripting unless necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ingest Pipeline and Update by Query
&lt;/h2&gt;

&lt;p&gt;Ingest nodes in Elasticsearch are used to pre-process documents before they are indexed. By default, all nodes in a cluster are ingest nodes. They can be separated if the ingest process is resource-intensive. Pipelines define the pre-processor. They contain a "description" and a "processor". The processor is a series of steps that are carried out on the document. They can contain Logstash grok patterns and scripting like Painless.&lt;/p&gt;

&lt;p&gt;First, let us see the pipeline definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; PUT &lt;span class="s2"&gt;"localhost:9200/_ingest/pipeline/my-pipeline-id"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;'
{
    description": "Used to update in place - Remove the alphanumeric ids from jobIdentifier in my_index index",
    "processors": [
        {
            "grok": {
                "field": "jobIdentifier",
                "patterns": [
                    "%{NEWFIELDIDS:eID}-%{NEWFIELDIDS:eSEQID}-%{NEWFIELDIDS:e2ID}-%{GREEDYDATA:REST}"
                ],
                "pattern_definitions": {
                    "NEWFIELDIDS": "[0-9]+"
                },
                "ignore_missing": true
            }
        },
        {
            "script": {
                "lang": "painless",
                "inline": "jobIdentifier = ctx.REST"
            }
        },
        {
            "script": {
                "lang": "painless",
                "inline": "ctx.remove('&lt;/span&gt;eID&lt;span class="s1"&gt;'); ctx.remove('&lt;/span&gt;eSEQID&lt;span class="s1"&gt;'); ctx.remove('&lt;/span&gt;e2ID&lt;span class="s1"&gt;');  ctx.remove('&lt;/span&gt;REST&lt;span class="s1"&gt;')"
            }
        }
    ]
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documents go through three processors in the pipeline.&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="nl"&gt;"grok"&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;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jobIdentifier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"patterns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"%{NEWFIELDIDS:eID}-%{NEWFIELDIDS:eSEQID}-%{NEWFIELDIDS:e2ID}-%{GREEDYDATA:REST}"&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;"pattern_definitions"&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;"NEWFIELDIDS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[0-9]+"&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;"ignore_missing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;Match the field “jobIdentifier”. Create a pattern named “NEWFIELDIDS” which has 1 or more numbers. If the field has a sequence of “Numbers-Numbers-Numbers-Other data”, then each number set is assigned a field name (eID, eSEQID, e2ID). Match the rest of the pattern until the end and assign this to field “REST”. This match is done using the inbuilt type “GREEDYDATA” from the Logstash grok patterns. At the end of this step, add the four new fields (eID, eSEQID, e2ID, REST) to the document. However, as mentioned before, there can be documents where the above field pattern might not match. In such cases, the pipeline stops. We do not want that. Hence we add “ignore_missing” as "true".&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="nl"&gt;"script"&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;"lang"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"painless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jobIdentifier = ctx.REST"&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;Now we run a Painless script. We take the newly created field “REST” and reassign the “jobIdentifier” field as this value.&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="nl"&gt;"script"&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;"lang"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"painless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ctx.remove('eID'); ctx.remove('eSEQID'); ctx.remove('e2ID');  ctx.remove('REST')"&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;Finally, we remove the newly created fields in step 1 (eID, eSEQID, e2ID, REST) as we do not need them anymore.&lt;/p&gt;

&lt;p&gt;The explanation looks enormous, but we basically matched the pattern, updated the field, and then removed the extra new fields created.&lt;/p&gt;

&lt;p&gt;Finally using the newly created pipeline (identified by “my-pipeline-id”), we run an Update by Query on the index. We match the documents whose fields match the requisite pattern and pass them through the pipeline. We can use multiple indices in the field to run documents from multiple indices. We use &lt;code&gt;wait_for_completion&lt;/code&gt; as false, so the query returns immediately and the update happens in the background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"localhost:9200/my_index/_update_by_query?pipeline=my-pipeline-id&amp;amp;wait_for_completion=false"&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"query"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"bool"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"must"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"regexp"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="s2"&gt;"jobIdentifier"&lt;/span&gt;: &lt;span class="s2"&gt;"[0-9]+-[0-9]+-[0-9]+-(.*)"&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;We might not need the expensive regular expressions in scripting while matching/updating fields in Elasticsearch. Instead of enabling it blindly in our cluster, we can first try a pipeline and "update by query", which can certainly meet our needs in most common cases.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>elasticsearch</category>
    </item>
    <item>
      <title>Networking Basics - RIP</title>
      <dc:creator>Shubhojyoti</dc:creator>
      <pubDate>Sun, 07 Jul 2019 17:07:20 +0000</pubDate>
      <link>https://dev.to/shubho/networking-basics-rip-eod</link>
      <guid>https://dev.to/shubho/networking-basics-rip-eod</guid>
      <description>&lt;p&gt;One of the first routing protocol that you would ever learn is the Routing Information Protocol (RIP). It is an Interior Gateway Protocol (IGP), and it uses a distance-vector algorithm called Bellman-Ford Algorithm. Here are my brief notes on what the protocol is and how it works.&lt;/p&gt;

&lt;p&gt;The protocol has two versions RIPv1 and RIPv2. Both are in use today and have significant differences.  UDP is used to transmit updated. The UDP port is 520. The IPv6 version is called RIPng.&lt;/p&gt;

&lt;p&gt;Neighbors exchange their complete routing table at regular interval of 30 seconds (default). This is called the update timer. There is no session formation between RIP neighbors. Once RIP is enabled on a network subnet, it immediately starts sending the RIP updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Differences between RIPv1 and RIPv2
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;RIPv1&lt;/th&gt;
&lt;th&gt;RIPv2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Update Message is sent to local subnet broadcast address viz. 255.255.255.0&lt;/td&gt;
&lt;td&gt;Update Message is sent to multicast address 224.0.0.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No authentication support is available&lt;/td&gt;
&lt;td&gt;Support available for both plain text and MD5 authentication.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VLSM support not present. Hence RIPv1 is classful. Only the default subnet masks of Class A (/8), Class B (/16) and Class C (/24) addresses are used. These subnet masks are not sent in the updates. When the routes are received, the masks are derived from the addresses.&lt;/td&gt;
&lt;td&gt;Supports VLSM. The subnet mask is carried in the updates and hence RIPv2 is classless. Also RIPv2 can still come up when a network is discontiguous due to this feature.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Doesn’t allow a router to advertise a different next-hop router than itself.&lt;/td&gt;
&lt;td&gt;Supports Next Hop field in the Update message. Hence a router can specify another router as a next-hop.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  RIP Timers
&lt;/h2&gt;

&lt;p&gt;RIP uses four different timers which help in maintaining the routing table and helps in avoiding loops. All these timers are per route. These are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Update timer&lt;/strong&gt; (30 secs) – This is the interval which states how often the update for a specific route must be sent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalid timer&lt;/strong&gt; (180 secs) – This is the interval which states that once an update is received for a route how long to wait till the route is considered invalid or non-reachable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold down timer&lt;/strong&gt; (180 secs) – If a route gets a worse metric and is updated, the hold down timer is started. During this time no other metric for the route is accepted which is equal or worse than the current metric.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flush or Garbage timer&lt;/strong&gt; (240 secs) – This is the interval which states how long to wait since the last valid update before removing the route from the routing table.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whenever a valid update is received from a neighbor, the update, invalid and flush timer resets to 0. The hold down timer resets to 0 whenever a metric value decreases.&lt;/p&gt;

&lt;p&gt;RIP uses hop count as the metric. So in case, a prefix is received from multiple paths, the prefix with a smaller no of hops will be preferred. RIP allows up to 15 hops. 16 hops and above are considered to be infinite, and those routes are deemed to be unreachable. This limit in the number of hops prevents loops. Unlike other protocols like OSPF and ISIS, which are link state protocols and whose implementation itself ensures loop-free network, RIP uses some specific concepts which help in loop prevention. This makes RIP a great protocol in terms of implementation, but this also introduces a more substantial convergence time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loop Prevention Concepts in RIP
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Split Horizon&lt;/strong&gt; – Even though in RIP the entire routing table is sent to the neighbors, RIP omits the routes which has been advertised by the neighbor to whom the update is being sent. In other words, if the outgoing interface of a route matches the interface out of which the new update is to be sent, then that route is omitted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route Poisoning&lt;/strong&gt; – When a route’s reachability fails, the update is sent with the metric of that route as 16 (infinite) thereby specifying to the neighbors that the route is unreachable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poison Reverse&lt;/strong&gt; – In this case, the route with an infinite metric is advertised out the same interface through which it is received with the same infinite metric. Split Horizon with Poison Reverse is used together in most of the cases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.shubho.dev/blog/networking-basics-rip" rel="noopener noreferrer"&gt;Shubho.Dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Featured Image courtesy &lt;a href="https://unsplash.com/@aligns" rel="noopener noreferrer"&gt;Jordan Harrison&lt;/a&gt; at Unsplash&lt;/p&gt;

</description>
      <category>networking</category>
      <category>rip</category>
    </item>
    <item>
      <title>Backup NextCloud data to Dropbox</title>
      <dc:creator>Shubhojyoti</dc:creator>
      <pubDate>Fri, 05 Jul 2019 23:04:03 +0000</pubDate>
      <link>https://dev.to/shubho/backup-nextcloud-data-to-dropbox-59kc</link>
      <guid>https://dev.to/shubho/backup-nextcloud-data-to-dropbox-59kc</guid>
      <description>&lt;p&gt;Dropbox is the primary cloud sync provider in my family. All our personal documents, family photographs, code projects etc. live there. Folder common to both my wife and I are shared between our accounts. Everything else remains separate. We also backup the data to external hard drives. My personal MacBook also uses Backblaze. We overdo our backup strategy due to a data loss incident couple of years back.&lt;/p&gt;

&lt;p&gt;We also have Nextcloud on a Debian system in our home network. It suffices as our media centre.  I wanted to create a backup system for the Nextcloud installation. I didn’t want to use S3 or anything else at this point as our Nextcloud instance is not a huge data hog. So I am using my existing Dropbox instance for this. Nextcloud allows Dropbox to be used as an external storage. But I use my local HDD as the storage for Nextcloud and then rsync it to a Dropbox folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial setup for Dropbox
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;On the host machine (where Nextcloud is installed), install Dropbox. This process will vary based on your operating system. &lt;/li&gt;
&lt;li&gt;Create a folder “NEXTCLOUD-BKP” in Dropbox. Make it a shared folder if required. &lt;/li&gt;
&lt;li&gt;Using the Selective Sync feature remove all other folders except the newly created one. Since the primary purpose of my Debian system is Nextcloud, I am only syncing the backup folder for Dropbox and not any other data.&lt;/li&gt;
&lt;li&gt;This step is specific for my setup. My Nextcloud instance uses Apache web server and runs as &lt;em&gt;www-data&lt;/em&gt; user. But my Dropbox is installed as the main logged in user. In order to enable me to copy the data owned by &lt;em&gt;www-data&lt;/em&gt; user, add the logged in user to &lt;em&gt;www-data&lt;/em&gt; group. &lt;code&gt;usermod -a -G www-data &amp;lt;LOGGED_IN_USER&amp;gt;&lt;/code&gt;. Make the permissions of the “NEXTCLOUD-BKP” folder to g+rwx. &lt;code&gt;chmod g+rwx ~/Dropbox/NEXTCLOUD-BKP&lt;/code&gt;. Ensure that the Dropbox and “NEXTCLOUD-BKP” folder has “x” bit set to enable the &lt;em&gt;www-data&lt;/em&gt; user to copy to its subfolders. &lt;a href="https://askubuntu.com/questions/455000/group-permissions-allow-but-still-get-permission-denied" rel="noopener noreferrer"&gt;https://askubuntu.com/questions/455000/group-permissions-allow-but-still-get-permission-denied&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Enable maintenance mode on Nextcloud
&lt;/h2&gt;

&lt;p&gt;This locks the sessions of existing logged in users to prevent inconsistency in the database. It also prevents new logins. &lt;code&gt;php $NEXTCLOUD_PATH/occ maintenance:mode --on&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy the Nextcloud data using rsync
&lt;/h2&gt;

&lt;p&gt;You can either copy the whole Nextcloud folder or just the data, config and themes folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rsync &lt;span class="nt"&gt;-Aavx&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/data ~/Dropbox/NEXTCLOUD-BKP
rsync &lt;span class="nt"&gt;-Aavx&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/config ~/Dropbox/NEXTCLOUD-BKP
rsync &lt;span class="nt"&gt;-Aavx&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/themes ~/Dropbox/NEXTCLOUD-BKP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Backup Nextcloud database
&lt;/h2&gt;

&lt;p&gt;My Nextcloud database is MariaDB. If you use PostgreSQL or SQLite, then this step will be different for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Database name is nextcloud&lt;/span&gt;
/usr/bin/mysqldump &lt;span class="nt"&gt;--defaults-extra-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$MYSQL_CREDENTIALS_FILE&lt;/span&gt; &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--databases&lt;/span&gt; nextcloud &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/Dropbox/NEXTCLOUD-BKP/database/nc-db-bkp_&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%Y-%m-%d-%H-%M"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;.bak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;$MYSQL_CREDENTIALS_FILE&lt;/code&gt; provides the username and password for the next cloud database. &lt;a href="https://dev.mysql.com/doc/refman/5.5/en/option-files.html" rel="noopener noreferrer"&gt;https://dev.mysql.com/doc/refman/5.5/en/option-files.html&lt;/a&gt; &lt;code&gt;nextcloud&lt;/code&gt; is the name of the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update permissions of the backup folders created/updated
&lt;/h2&gt;

&lt;p&gt;This step will depend on your setup and might be completely optional. Since I have different user running nextcloud, I need to do this for Dropbox to read the newly created files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/data
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/config
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/themes
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since my installation is within my home network and is behind a firewall and opens only the required ports, I feel safe doing the above. YMMV.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable maintenance mode on Nextcloud
&lt;/h2&gt;

&lt;p&gt;Once all the above steps are done, disable the maintenance mode. &lt;code&gt;php $NEXTCLOUD_PATH/occ maintenance:mode --on&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup a cron
&lt;/h2&gt;

&lt;p&gt;I run the script once a day at 9PM. &lt;code&gt;0 21 * * * nextcloud-backup.sh&lt;/code&gt;. The script must run as the &lt;em&gt;www-data&lt;/em&gt; user or the user running the nextcloud process. Here is the complete script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="c"&gt;# Can set the below three as environment variables or uncomment to set actual paths&lt;/span&gt;
&lt;span class="nv"&gt;NEXTCLOUD_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;NEXTCLOUD_INSTALLATION_PATH&amp;gt;
&lt;span class="nv"&gt;DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;PATH_TO_NEXTCLOUD_BACKUP_FOLDER_IN_DROPBOX&amp;gt;
&lt;span class="nv"&gt;MYSQL_CREDENTIALS_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;MYSQL_CREDENTIALS_FILE_CONF_FORMAT&amp;gt;

&lt;span class="nv"&gt;PHP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;which php&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;MYSQLDUMP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;which mysqldump&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="c"&gt;# Enable Maintenance mode&lt;/span&gt;
&lt;span class="nv"&gt;$PHP_PATH&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/occ maintenance:mode &lt;span class="nt"&gt;--on&lt;/span&gt;

&lt;span class="c"&gt;# Backup data, config and themes from nextcloud directory.&lt;/span&gt;
&lt;span class="c"&gt;# Can sync the entire nextcloud directory if needed&lt;/span&gt;
rsync &lt;span class="nt"&gt;-Aavx&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/data &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;
rsync &lt;span class="nt"&gt;-Aavx&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/config &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;
rsync &lt;span class="nt"&gt;-Aavx&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/themes &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;

&lt;span class="c"&gt;# Backup MySQL&lt;/span&gt;
&lt;span class="nv"&gt;$MYSQLDUMP_PATH&lt;/span&gt; &lt;span class="nt"&gt;--defaults-extra-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$MYSQL_CREDENTIALS_FILE&lt;/span&gt; &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--databases&lt;/span&gt; nextcloud &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/database/nc-db-bkp_&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%Y-%m-%d-%H-%M"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;.bak

&lt;span class="c"&gt;# Update permissions of the backup path to 777 (Because the user running nextcloud is different.)&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/data
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/config
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/themes
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 777 &lt;span class="nv"&gt;$DROPBOX_NEXTCLOUD_PATH&lt;/span&gt;/database

&lt;span class="c"&gt;# Disable Maintenance mode&lt;/span&gt;
&lt;span class="nv"&gt;$PHP_PATH&lt;/span&gt; &lt;span class="nv"&gt;$NEXTCLOUD_PATH&lt;/span&gt;/occ maintenance:mode &lt;span class="nt"&gt;--off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides a good setup for me and my Nextcloud data is backed up to Dropbox. Please note that the &lt;code&gt;mysqldump&lt;/code&gt; is not incremental. So you might need to delete older files if required. I keep 5 days backup only as the actual data folder is completely overwritten by &lt;code&gt;rsync&lt;/code&gt;. You can update the &lt;code&gt;rsync&lt;/code&gt; commands by creating an archive and saving instead of actual copy.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.shubho.dev/blog/backup-nextcloud-data-to-dropbox" rel="noopener noreferrer"&gt;Shubho.Dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Featured Image courtesy &lt;a href="https://pixabay.com/users/www_darkworkx_de-2044000/" rel="noopener noreferrer"&gt;Dirk Wouters&lt;/a&gt; at Pixabay&lt;/p&gt;

</description>
      <category>nextcloud</category>
      <category>dropbox</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
