<?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: Sebastian Scheibe</title>
    <description>The latest articles on DEV Community by Sebastian Scheibe (@ecostack).</description>
    <link>https://dev.to/ecostack</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%2F265207%2Fe4cc250b-ae30-4f54-918f-63e8e98e5fcc.jpeg</url>
      <title>DEV Community: Sebastian Scheibe</title>
      <link>https://dev.to/ecostack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ecostack"/>
    <language>en</language>
    <item>
      <title>Part 2: Parse website HTML with NodeJS and cheerio</title>
      <dc:creator>Sebastian Scheibe</dc:creator>
      <pubDate>Mon, 04 May 2020 15:37:12 +0000</pubDate>
      <link>https://dev.to/ecostack/part-2-parse-website-html-with-nodejs-and-cheerio-58bn</link>
      <guid>https://dev.to/ecostack/part-2-parse-website-html-with-nodejs-and-cheerio-58bn</guid>
      <description>&lt;p&gt;Hello back again! If you missed out on how to create the selector for HTML data, please check out part one of the series! Otherwise, let us proceed with the automatic parsing of the data!&lt;/p&gt;

&lt;p&gt;We begin with creating a new project. Open up your terminal and enter the following to create a &lt;strong&gt;NodeJS&lt;/strong&gt; project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;web-data-retrieve &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;web-data-retrieve &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After that, let us add &lt;strong&gt;got&lt;/strong&gt; (HTTP request client) and &lt;strong&gt;cheerio&lt;/strong&gt; (jQuery equivalent for NodeJS). The former will be used to request the content and the later to parse it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; cheerio got
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, let us create an index file which will contain our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;index.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open up the &lt;strong&gt;index.js&lt;/strong&gt; file and add the following code inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;cheerio&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;cheerio&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;got&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;got&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.marketwatch.com/investing/stock/aapl/financials&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="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;got&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;.financials tr.partialSum:nth-child(1) td.valueCell&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;cellData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;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="nx"&gt;cellData&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;error&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;log&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;response&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="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 let me explain what is going on here, top to bottom. The first two lines are the libraries we will be using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;cheerio&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;cheerio&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;got&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;got&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The next line is the URL which will be getting the content from, it is identical with the one from the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.marketwatch.com/investing/stock/aapl/financials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The next line is a bit more complex, it is a wrapper, which let us use asynchronous functions. To have that explained, it is better to follow another tutorial :). The more interesting part happens inside of it!&lt;/p&gt;

&lt;p&gt;The first line calls the library &lt;strong&gt;got&lt;/strong&gt; with the URL which was defined in the beginning of our file. It's response is saved in the &lt;strong&gt;response&lt;/strong&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;got&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="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;.financials tr.partialSum:nth-child(1) td.valueCell&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;cellData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;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="nx"&gt;cellData&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;error&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;log&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;response&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After that, the &lt;strong&gt;response&lt;/strong&gt; will be loaded with &lt;strong&gt;cheerio&lt;/strong&gt;. It gives us a query operator, similar to what was used with jQuery in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;got&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;.financials tr.partialSum:nth-child(1) td.valueCell&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;cellData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;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="nx"&gt;cellData&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;error&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;log&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;response&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What follows is the use of our selector which we created before in the browser. It will return us the selected elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;got&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;.financials tr.partialSum:nth-child(1) td.valueCell&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cellData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;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="nx"&gt;cellData&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;error&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;log&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;response&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The last magical line in the try converts the selected data to standard JS array which allows us to map over it. In the map we take the first child and look at its data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;got&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;.financials tr.partialSum:nth-child(1) td.valueCell&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;cellData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;line&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="nx"&gt;cellData&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;error&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;log&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;response&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The application will print out the sales for the Apple stocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# node index.js&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'231.28B'&lt;/span&gt;, &lt;span class="s1"&gt;'214.23B'&lt;/span&gt;, &lt;span class="s1"&gt;'228.57B'&lt;/span&gt;, &lt;span class="s1"&gt;'265.81B'&lt;/span&gt;, &lt;span class="s1"&gt;'259.97B'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Where to go from here? Well, you can modify the application in ways to retrieve more data of the Apple stock or even fetch different stocks. The possibilities are endless, whatever suits your purpose.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sindresorhus/got"&gt;https://github.com/sindresorhus/got&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cheerio.js.org"&gt;https://cheerio.js.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.w3schools.com/jquery/jquery_ref_selectors.asp"&gt;https://www.w3schools.com/jquery/jquery_ref_selectors.asp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://api.jquery.com/category/selectors/"&gt;https://api.jquery.com/category/selectors/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>html</category>
      <category>scraping</category>
    </item>
    <item>
      <title>Part 1: Locating the HTML for the website data you are interested</title>
      <dc:creator>Sebastian Scheibe</dc:creator>
      <pubDate>Mon, 04 May 2020 15:37:05 +0000</pubDate>
      <link>https://dev.to/ecostack/part-1-locating-the-html-for-the-website-data-you-are-interested-3neg</link>
      <guid>https://dev.to/ecostack/part-1-locating-the-html-for-the-website-data-you-are-interested-3neg</guid>
      <description>&lt;p&gt;You maybe might be in the same position, you want to gather some data of different objects (like financial data from different entities) from a website, and you copy/paste thousands times from website to your local worksheet. The work of collection makes you exhausting. Believe me, I have been there as you did.&lt;/p&gt;

&lt;p&gt;To collect and format data more efficiently and nicely, we will create a little program to solve the problem for us. Afterwards, it will only take a few seconds to retrieve the online data.&lt;/p&gt;

&lt;p&gt;The article is split into two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;first part&lt;/strong&gt; introduces how to locate the data points we want in the HTML of the website. &lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;second part&lt;/strong&gt; shows you how to apply that knowledge in an automated way with a small NodeJS script.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This part is going to start with an example of collecting financial information of Apple Inc. from a stock market website, &lt;strong&gt;martketwatch.com&lt;/strong&gt;. &lt;br&gt;
The URL path is: &lt;a href=""&gt;https://www.marketwatch.com/investing/stock/aapl/financials&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The approach I will show is based on the assumption that there is no API available which could be used directly. In the case of &lt;strong&gt;martketwatch.com&lt;/strong&gt;, they render the data on the server, which means the rendered page needs to be parsed. So let us do that!&lt;/p&gt;

&lt;p&gt;Now, to help us research how to get to the precious data, let us make use of &lt;strong&gt;jQuery&lt;/strong&gt;. It has the same interface as &lt;strong&gt;cheerio&lt;/strong&gt;, which will be used later.&lt;/p&gt;

&lt;p&gt;To use &lt;strong&gt;jQuery&lt;/strong&gt; on the current website, execute the following in the developer console. It adds a script tag to the website which will load the jQuery library for our use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;script&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;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://code.jquery.com/jquery-latest.min.js&lt;/span&gt;&lt;span class="dl"&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;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Then the $ should be available. In case it is not available, maybe due to CSR policy of the website, the last option is to copy the content of &lt;a href=""&gt;https://code.jquery.com/jquery-latest.min.js&lt;/a&gt; and paste and execute it in the developer console.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Give it a test and select all input tags on the website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&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;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q7TWX8W9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iq297ll3qzg4qmf1nwxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q7TWX8W9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iq297ll3qzg4qmf1nwxp.png" alt="Result of $('input') command on **martketwatch.com**"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should now see that there are some input tags found by the &lt;strong&gt;jQuery&lt;/strong&gt; selector. This is great, the groundwork is laid for our adventure!&lt;/p&gt;




&lt;p&gt;Now, let us see how we can select the data we want, in this case, the financial data of the stocks of brand with a bitten fruit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---As6ewyv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a0vg61b8m7ca163s0jpj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---As6ewyv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a0vg61b8m7ca163s0jpj.png" alt="Apple stock data in the years 2015 to 2019"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The data we are interested here are the sales from the year 2015 to 2019, the question is, how can we extract them? Well, you might have guessed it, with the jQuery selector. Let us have a look at the HTML of it. With the element selector of your developers tools, you can select the element in the view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vHWhmZns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5frdrwdxr8gfl35fjdu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vHWhmZns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5frdrwdxr8gfl35fjdu3.png" alt="Element selection to find corresponding tag in HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting a field, the element will be located in the HTML.&lt;/p&gt;

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

&lt;p&gt;Looking at the surrounding HTML, there is a &lt;strong&gt;div&lt;/strong&gt; tag with the class &lt;strong&gt;financials&lt;/strong&gt;. Inside of that tag is the actual &lt;strong&gt;table&lt;/strong&gt; tag, which has a &lt;strong&gt;tbody&lt;/strong&gt; tag. That one contains a &lt;strong&gt;tr&lt;/strong&gt; tag which contains the &lt;strong&gt;td&lt;/strong&gt; tags with our precious data we want to collect! I hope you could follow me here so far :)&lt;/p&gt;

&lt;p&gt;Let us try to come up with a selector that will work for jQuery. Clearly the &lt;strong&gt;financials&lt;/strong&gt; class looks like a perfect anchor, due to being unique in the HTML. Next let us try to select only the class &lt;strong&gt;valueCell&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&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;.financials td.valueCell&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HWbk_Pi2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7cq4iqxdtrb19n1r1xlf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HWbk_Pi2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7cq4iqxdtrb19n1r1xlf.png" alt="Too many tags with class valueCell are selected"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now this is a bit to broad and we have too many &lt;strong&gt;valueCell&lt;/strong&gt; class tags selected, we need to narrow it down a bit. After looking at what kind of other tags were selected, it seems that we need to constrain it down to the first row of &lt;strong&gt;valueCell&lt;/strong&gt; class tags. Luckily, there is a &lt;strong&gt;tr&lt;/strong&gt; tag which has the class &lt;strong&gt;partialSum&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&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;.financials tr.partialSum:nth-child(1) td.valueCell&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;p&gt;This leaves us with exact the cells we want to look up! Next step is too use it in our automation!&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.w3schools.com/jquery/jquery_ref_selectors.asp"&gt;https://www.w3schools.com/jquery/jquery_ref_selectors.asp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://api.jquery.com/category/selectors/"&gt;https://api.jquery.com/category/selectors/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>node</category>
      <category>scraping</category>
    </item>
    <item>
      <title>#discuss Best course for functional programming?</title>
      <dc:creator>Sebastian Scheibe</dc:creator>
      <pubDate>Wed, 15 Apr 2020 19:18:02 +0000</pubDate>
      <link>https://dev.to/ecostack/discuss-best-course-for-functional-programming-14i9</link>
      <guid>https://dev.to/ecostack/discuss-best-course-for-functional-programming-14i9</guid>
      <description>&lt;p&gt;Hey everyone!&lt;/p&gt;

&lt;p&gt;What course would you recommend for learning functional programming which also incorporates real world examples? &lt;/p&gt;

&lt;p&gt;I read already materials on the subject but they mostly evolve around the basics. I would like to see a course/video/post where a small project is built from ground up in a functional approach.&lt;/p&gt;

&lt;p&gt;Any ideas?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>functional</category>
    </item>
    <item>
      <title>How to migrate from Sails.js to Express.js (or how to finally reach land)</title>
      <dc:creator>Sebastian Scheibe</dc:creator>
      <pubDate>Thu, 10 May 2018 10:23:34 +0000</pubDate>
      <link>https://dev.to/ecostack/how-to-migrate-from-sails-js-to-express-js-or-how-to-finally-reach-land-2e3b</link>
      <guid>https://dev.to/ecostack/how-to-migrate-from-sails-js-to-express-js-or-how-to-finally-reach-land-2e3b</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ARVia951vicq7LpQbISBlLw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ARVia951vicq7LpQbISBlLw.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the company I am working for we had a pretty large project written in &lt;em&gt;Sails.js&lt;/em&gt;. Now, after such a long time of development the project grew and grew and there was a need now for structural changes. Also it just became necessary to use a compiler for syntax checking.&lt;/p&gt;

&lt;p&gt;So, we introduced &lt;em&gt;TypeScript&lt;/em&gt;. This step was easy and could be quickly achieved with just a new &lt;em&gt;Grunt&lt;/em&gt; task and some modifications at the folder structure.&lt;/p&gt;

&lt;p&gt;There is just one thing in &lt;em&gt;Sails.js&lt;/em&gt; which made &lt;em&gt;TypeScript&lt;/em&gt; less powerful_._ It makes all controllers, services and models available to the &lt;strong&gt;GLOBAL&lt;/strong&gt; variable. This limits the possibilities of &lt;em&gt;TypeScript&lt;/em&gt; since &lt;em&gt;Sails.js&lt;/em&gt; always expects&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
 ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;to be set.&lt;/p&gt;

&lt;p&gt;With that size of a code base, it just becomes necessary to rely on features like type checking and code completion from &lt;em&gt;TypeScript&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For these features we needed to implement classes. Now, having classes and the &lt;em&gt;Node.js&lt;/em&gt; standard export &lt;strong&gt;module.exports&lt;/strong&gt; is not such an ideal combination.&lt;/p&gt;

&lt;p&gt;A class looked like this:&lt;/p&gt;


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



&lt;p&gt;So, after some try and error, it seemed like the keyword &lt;strong&gt;export&lt;/strong&gt; would work for &lt;em&gt;Sails.js&lt;/em&gt; and we could use our required features from &lt;em&gt;TypeScript&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This concept worked for some time, but in the end we faced sometimes issues with functions not being defined, depending on how the instance was accessed, via &lt;strong&gt;GLOBAL&lt;/strong&gt; or via an import of the file.&lt;/p&gt;

&lt;p&gt;This brought me then to the idea of the removal of &lt;em&gt;Sails.js&lt;/em&gt; and the implementation of &lt;em&gt;Express.js&lt;/em&gt; in combination with a full class driven approach for our code base.&lt;/p&gt;

&lt;p&gt;It had also another huge benefit.&lt;/p&gt;

&lt;p&gt;We could finally group files into sub folders. This was not possible, since &lt;em&gt;Sails.JS&lt;/em&gt; just reads the first layer of the folders it works with (services, controllers, models).&lt;/p&gt;

&lt;h3&gt;
  
  
  The migration guide
&lt;/h3&gt;

&lt;p&gt;So, how did we migrate in the end?&lt;/p&gt;

&lt;p&gt;After some research of what modules are needed, it was more a task of &lt;strong&gt;try and error&lt;/strong&gt; to see if the application boots and the unit tests are still running. :)&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom app.js and server.ts(js) file
&lt;/h4&gt;

&lt;p&gt;So, first step is to create a custom entry file for the application.&lt;/p&gt;

&lt;p&gt;First, we created a new &lt;strong&gt;app.js&lt;/strong&gt; and a &lt;strong&gt;server.ts&lt;/strong&gt; file. The &lt;strong&gt;server.ts&lt;/strong&gt; was created somewhere in the source directory and being a TypeScript file it has the benefits of being checked by the compiler.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;app.js&lt;/strong&gt; file in the root folder would just call the compiled version of the &lt;strong&gt;server.ts&lt;/strong&gt; file to start the application.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;server.ts&lt;/strong&gt; file would look like your average &lt;em&gt;Express.js&lt;/em&gt; file except that you would add some extra in there, to make it work like &lt;em&gt;Sails.js&lt;/em&gt; in the beginning.&lt;/p&gt;

&lt;p&gt;Constructing the server file was the major part of the migration, in the end.&lt;/p&gt;

&lt;p&gt;There are a couple of things that need to be done:&lt;/p&gt;

&lt;h4&gt;
  
  
  Global Sails.js object
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Sails.js&lt;/em&gt; makes an object globally available which contains features like logging, config object, i18n.&lt;/p&gt;

&lt;p&gt;To get the code up and running, it was the easiest to just simulate this behaviour:&lt;/p&gt;


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


&lt;p&gt;Setup all the middleware&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSRF&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;Locals (translations)&lt;/li&gt;
&lt;li&gt;wantsJSON (which has the same behaviour as Sails.js)&lt;/li&gt;
&lt;li&gt;Skipper (file uploads)&lt;/li&gt;
&lt;li&gt;Default response methods (res.ok() / res.serverError()/ …)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Routing and policies
&lt;/h4&gt;

&lt;p&gt;In &lt;em&gt;Sails.js&lt;/em&gt; the routing and the policies are both set up with files, not in the code itself. This makes the migration quite time intensive, if you need to rewrite every route and its policies into code for the &lt;em&gt;Express.js&lt;/em&gt; router setup.&lt;/p&gt;

&lt;p&gt;If the application is small, this would be not a huge problem. Our application though contains 700 REST routes and the equivalent amount of policies.&lt;/p&gt;

&lt;p&gt;In the end, I ended up writing two parsers. One for the route setup, which would parse the &lt;strong&gt;routes.js&lt;/strong&gt; and one for the policies, which would parse the &lt;strong&gt;policies.js&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;This had also the huge benefit of other developers could just proceed with their day to day development and extend these files all while I was modifying the core parts of the application. Business as usual could proceed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Template engine
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Sails.js&lt;/em&gt; uses by default the &lt;strong&gt;EJS&lt;/strong&gt; template engine.&lt;/p&gt;

&lt;p&gt;This gave me a bit trouble, since the default setup of &lt;strong&gt;EJS&lt;/strong&gt; did not work from the beginning with the setup of our &lt;strong&gt;EJS&lt;/strong&gt; templates. There was an issue with how we use sub templates.&lt;/p&gt;

&lt;p&gt;After some experimentation I found that it works properly with the package &lt;strong&gt;express-ejs-layouts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This was the setup in the server file:&lt;/p&gt;


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


&lt;p&gt;Also the render methods needed to be changed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sails.js&lt;/em&gt; implements a behaviour which, based on the controller, detects the correct template file.&lt;/p&gt;

&lt;p&gt;The migration would go from:&lt;/p&gt;


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


&lt;p&gt;to:&lt;/p&gt;


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


&lt;h4&gt;
  
  
  &lt;strong&gt;What about the database layer?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Sails.js&lt;/em&gt; uses its own written database connector, &lt;strong&gt;Waterline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This made it a bit more complex since &lt;strong&gt;Waterline&lt;/strong&gt; is made to run inside of &lt;em&gt;Sails.js&lt;/em&gt;. Now that there is no &lt;em&gt;Sails.js&lt;/em&gt; anymore, how would you trigger the startup? The documentation of the Github page does not give a lot of information on how to work with &lt;strong&gt;Waterline&lt;/strong&gt; in your own project.&lt;/p&gt;

&lt;p&gt;After some debugging of the documentation I came up with a class which replicates the behaviour of &lt;em&gt;Sails.js&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The startup method would be called during the &lt;em&gt;Express.js&lt;/em&gt; startup.&lt;/p&gt;

&lt;p&gt;I came up with this:&lt;/p&gt;


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


&lt;p&gt;Also I made it possible to access the model via the import and have the functions of &lt;strong&gt;Waterline&lt;/strong&gt; available (find()/remove()/save()/…).&lt;/p&gt;

&lt;p&gt;A model can now look like this:&lt;/p&gt;


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


&lt;h4&gt;
  
  
  Socket.IO
&lt;/h4&gt;

&lt;p&gt;Since we rely heavily on the socket implementation, we were in need to reimplement in nearly the same way.&lt;/p&gt;

&lt;p&gt;To init the socket.io we first init the express server. The instance we get from the express server is then used to initiate an instance of socket.io.&lt;/p&gt;


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


&lt;p&gt;Here we use the Redis adapter to keep multiple instances of our application synchronised.&lt;/p&gt;

&lt;p&gt;The cookie parser is being used to, as it says, parse the cookies on the first connection from a browser.&lt;/p&gt;

&lt;p&gt;After that the Socket.io instance gets started and as the final stage, there is some middleware applied to the Socket.io instance.&lt;/p&gt;


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


&lt;p&gt;In the monitor you can listen on events which are coming in.&lt;/p&gt;

&lt;p&gt;As you can see, this methods differs from the controller mapping approach of the &lt;em&gt;Sails.js&lt;/em&gt; &lt;em&gt;Socket.io&lt;/em&gt; implementation. It should not be too difficult to adapt to the &lt;em&gt;Socket.io&lt;/em&gt; event listening approach.&lt;/p&gt;

&lt;h4&gt;
  
  
  Last words
&lt;/h4&gt;

&lt;p&gt;I am very happy with how everything turned out and how it works.&lt;/p&gt;

&lt;p&gt;The next step for the future would be the migrate away from Waterline and towards Mongoose.&lt;/p&gt;

&lt;p&gt;I hope you had the patience to read until this point and it might be helpful for you.&lt;/p&gt;

</description>
      <category>node</category>
      <category>waterline</category>
      <category>sailsjs</category>
      <category>express</category>
    </item>
  </channel>
</rss>
