<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>ExpressJS on Techformist</title>
    <link>https://techformist.com/tags/expressjs/</link>
    <description>Recent content in ExpressJS on Techformist</description>
    <image>
      <url>https://techformist.com/logo.svg</url>
      <link>https://techformist.com/logo.svg</link>
    </image>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 09 Dec 2020 06:30:00 +0000</lastBuildDate><atom:link href="https://techformist.com/tags/expressjs/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Create a Blog With Express, Markdown and Postgres</title>
      <link>https://techformist.com/create-blog-express-markdown-postgres/</link>
      <pubDate>Wed, 09 Dec 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-blog-express-markdown-postgres/</guid>
      <description>&lt;p&gt;Express is like a dear friend who does not leave your side during happy or sad times in your life. She may not help you reach enlightenment, but she&amp;rsquo;s there and she&amp;rsquo;s super supportive. And, that&amp;rsquo;s all you need many a time.&lt;/p&gt;
&lt;p&gt;In this post we create a blog with ExpressJS and friends - oh how exciting. Our blog is going to look beautiful with -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ExpressJS (of course)&lt;/li&gt;
&lt;li&gt;Ejs for templating. Has SSR built-in - for you SPA crazies&lt;/li&gt;
&lt;li&gt;Supports content authoring in markdown&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;rsquo;s how it looks -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Express is like a dear friend who does not leave your side during happy or sad times in your life. She may not help you reach enlightenment, but she&rsquo;s there and she&rsquo;s super supportive. And, that&rsquo;s all you need many a time.</p>
<p>In this post we create a blog with ExpressJS and friends - oh how exciting. Our blog is going to look beautiful with -</p>
<ol>
<li>ExpressJS (of course)</li>
<li>Ejs for templating. Has SSR built-in - for you SPA crazies</li>
<li>Supports content authoring in markdown</li>
</ol>
<p>Here&rsquo;s how it looks -</p>
<p><img loading="lazy" src="/2020/express-postgress-blog-sample-app.gif" type="" alt="express-postgress-blog-sample-app"  /></p>
<h2 id="why-expressjs">Why ExpressJS?</h2>
<p>First, I am kind of sad that this question came up - I mean, re-read [paragraph 1]. But since you asked - I continue to chose ExpressJS because-</p>
<ol>
<li>It is so darn easy to start and continue rocking</li>
<li>Large community = lot of solved problems</li>
<li>A tonne of useful code, plugins, middleware and so on</li>
</ol>
<p>I am more firmly in the SPA camp nowadays and love the productivity of a Vue application + standard styling libraries. But hey, Express and server-side templating keeps things real simple.</p>
<h2 id="get-started-setup">Get Started: Setup</h2>
<p>Install <a href="https://nodejs.org/en/download/">Node</a> and <a href="https://code.visualstudio.com/download">VSCode</a> if you don&rsquo;t already have them.</p>
<p>Create a new folder in some corner of your computer, name it <code>bloggie</code>, and open VSCode in that folder.</p>
<p>Open a terminal (in Windows, Mac or in VSCode - I don&rsquo;t judge), ensure that you are in the project folder, and key in the command to initiate the project.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm init -y
</span></span></code></pre></div><p><img loading="lazy" src="/2020/express-blog-app-start.jpg" type="" alt="express-blog-app-start"  /></p>
<p>It&rsquo;s time for that pat on your back - 25% of the work is already done.</p>
<p>Install a few packages that will be used in the project. We will see their purpose in a bit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save express ejs pg knex dotenv
</span></span></code></pre></div><p>Here&rsquo;s how the packages will be used..</p>
<ul>
<li><code>express</code>: App server</li>
<li><code>ejs</code>: Templating language that allows us to specify variables in standard HTML</li>
<li><code>pg</code>: Connect and run queries on postgres DB</li>
<li><code>dotenv</code>: Get variables from an environment file</li>
</ul>
<p>Install dev dependencies, which are packages used to get stuff done during development, but are not needed in production.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save-dev nodemon knex
</span></span></code></pre></div><p>Here we have -</p>
<ul>
<li><code>nodemon</code>: automatically restarts server when files are changes</li>
<li><code>knex</code>: Query builder that makes writing dynamic queries a wee bit easier</li>
</ul>
<p>You can install <code>knex</code> globally with <code>npm i -g knex</code> if you are going to use knex commands every now and then. The advantage of using global knex is that you don&rsquo;t need to explicitly reference knex within <code>node_modules</code>. Either ways, it is a good idea to include knex as an explicit dependency to also let others know of its gracious presence.</p>
<p>Create a folder in the project root folder and call it <code>public</code>. This folder will host all the assets exposed to the internet - like css, images, etc.</p>
<p>Next, install Postgres database server. The easiest way to do it is to download <a href="https://laragon.org/download/index.html">Laragon</a>, and click on a few buttons to install Postgres database.</p>
<p>We now have everything to get started.</p>
<h2 id="getting-started-first-steps">Getting Started: First Steps</h2>
<p>Create a new file in the project folder called <code>app.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// setup
</span></span></span><span class="line"><span class="cl"><span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dotenv&#34;</span><span class="p">).</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s2">&#34;view engine&#34;</span><span class="p">,</span> <span class="s2">&#34;ejs&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="s2">&#34;public&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="nx">extended</span><span class="o">:</span> <span class="kc">false</span> <span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">9000</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;App listening on port 9000.&#34;</span><span class="p">));</span>
</span></span></code></pre></div><p>With a few lines of code we created an Express server.</p>
<ul>
<li><code>require(&quot;dotenv&quot;).config()</code> allows us to define and use environment variables</li>
<li><code>app.set(&quot;view engine&quot;, &quot;ejs&quot;)</code> lets use <code>ejs</code> templating engine, which is a way to introduce variables within HTML</li>
<li><code>app.use(express.static(&quot;public&quot;));</code> enables us to store static assets in <code>public</code> folder and use that in our app</li>
<li><code>app.use(express.urlencoded({ extended: false }))</code> will allow us to use parameters in the URL - we will see more of this</li>
</ul>
<p>Include a command in your <code>package.json</code> to run your app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;bloggie&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.0.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;main&#34;</span><span class="p">:</span> <span class="s2">&#34;app.js&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;scripts&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;dev&#34;</span><span class="p">:</span> <span class="s2">&#34;nodemon app.js&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// other lines
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You can now start your express app with the command -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm run dev
</span></span></code></pre></div><p>See the line <code>App listening on port 9000.</code> and rejoice. Try making any changes to a file and see the server automatically restart - ah, the joy of modern programming.</p>
<h2 id="create-database">Create Database</h2>
<p>Any modern web app has several layers to it. We typically -</p>
<ul>
<li>design &ldquo;top-down&rdquo;: think about how your app flows, how screens are used and drill-down to specifics - where the business logic is implemented and data gets stored</li>
<li>develop &ldquo;bottom-up&rdquo;: start assembling blocks from the bottom layer and build out</li>
</ul>
<p>So, let&rsquo;s start creating them tables. <code>knex</code> makes it a breeze.</p>
<p>Get started by creating the knex init file - <code>knexfile.js</code>. You can do that by entering the below command..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx knex init
</span></span></code></pre></div><p>.. or reference knex using the full path relative to your project root folder.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node_modules/.bin/knex init
</span></span></code></pre></div><p>If you have installed <code>knex</code> globally, you could simply use <code>knex</code> like any other DOS command in the terminal.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">knex init
</span></span></code></pre></div><p>Change <code>knexfile.js</code> file to specify our database and connection settings -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// Update with your config settings.
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">development</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">client</span><span class="o">:</span> <span class="s2">&#34;postgresql&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">connection</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">database</span><span class="o">:</span> <span class="s2">&#34;bloggie&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">user</span><span class="o">:</span> <span class="s2">&#34;postgres&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">password</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">pool</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">min</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">max</span><span class="o">:</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">migrations</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">tableName</span><span class="o">:</span> <span class="s2">&#34;knex_migrations&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">directory</span><span class="o">:</span> <span class="s2">&#34;data/migrations&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>The configuration is fairly straight forward -</p>
<ol>
<li>Specify a database and user id/ password to connect</li>
<li>Specify a pool. A pool persists connections even after a transaction is completed and allows the next transaction to reuse connection. This saves execution time</li>
<li>We also specify the name of the table that stores the migration history - <code>knex_migrations</code>, and the directory where table definitions and seed data is stored - <code>data/migrations</code></li>
</ol>
<p>Create <code>data</code> and <code>migrations</code> directories.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">mkdir</span> data
</span></span><span class="line"><span class="cl"><span class="k">mkdir</span> data/migrations
</span></span></code></pre></div><p>Create your first migration file called <code>&lt;wierd_number&gt;_init.js</code>. A migration file allows you to simplify creating tables and also version controlling table changes made at different times.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">knex migrate:make init
</span></span></code></pre></div><p>Change the file to include table definitions. We will create a table to store blog posts and call it <code>posts</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">exports</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">knex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">knex</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">createTable</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">table</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">increments</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">timestamp</span><span class="p">(</span><span class="s2">&#34;created_at&#34;</span><span class="p">).</span><span class="nx">defaultTo</span><span class="p">(</span><span class="nx">knex</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">now</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">timestamp</span><span class="p">(</span><span class="s2">&#34;updated_at&#34;</span><span class="p">).</span><span class="nx">defaultTo</span><span class="p">(</span><span class="nx">knex</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">now</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;title&#34;</span><span class="p">).</span><span class="nx">notNullable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="s2">&#34;content&#34;</span><span class="p">).</span><span class="nx">notNullable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="mi">100</span><span class="p">).</span><span class="nx">unique</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;tags&#34;</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">exports</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">knex</span><span class="p">,</span> <span class="nb">Promise</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">knex</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">dropTable</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Next, let us apply this migration to the database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">knex migrate:up
</span></span></code></pre></div><p>If everything goes well we will see table <code>posts</code> created in the database. You can verify it by connecting to your Postgres DB using database client programs like pgadmin4 (typically installed with Postgres in dev environment) or <a href="https://www.heidisql.com/">HeidiSQL</a>.</p>
<p>Before we go any further, create a file to facilitate easy import of knex libraries in our project - <code>data/db.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">environment</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span> <span class="o">||</span> <span class="s2">&#34;development&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;../knexfile.js&#34;</span><span class="p">)[</span><span class="nx">environment</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;knex&#34;</span><span class="p">)(</span><span class="nx">config</span><span class="p">);</span>
</span></span></code></pre></div><p>You can test the connection by adding following lines in <code>app.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./data/db&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">);</span>
</span></span></code></pre></div><p>This should output an empty array since the table does not have any rows yet. You can delete the above lines once testing is complete - we don&rsquo;t quite need them.</p>
<h2 id="routes-in-express">Routes in Express</h2>
<p>Remember that Express server is running on port 9000? Go to a browser and enter <code>http://localhost:9000</code> to see a blank page. Real-world web applications do magic with these URLs - you could have -</p>
<ul>
<li><code>http://localhost:9000/blog</code>: to show posts from your blog</li>
<li><code>http://localhost:9000/users</code>: to display all users of your app</li>
</ul>
<p>Of course you have to build functionality in your server to provide information back to user when she enters the URL. These URLs are what are called routes for your app. ExpressJS can identify routes and you can enter your own functions to call for specific routes.</p>
<p>Just add following lines to <code>app.js</code> to create a new route -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&#34;hello world&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Save the file and go to <code>http://localhost:9000/hello</code> in your browser to see <code>hello world</code> message.</p>
<p>An app can have many routes and it is going to make our <code>app.js</code> look bad. Let&rsquo;s put these routes in a different file. Create a new folder called <code>routes</code> in project root and create a file therein called <code>index.js</code>. Fill this file with the same code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&#34;hello world&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>Import this file in <code>app.js</code>..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// setup
</span></span></span><span class="line"><span class="cl"><span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dotenv&#34;</span><span class="p">).</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="s2">&#34;public&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="nx">extended</span><span class="o">:</span> <span class="kc">false</span> <span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./routes/index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="nx">router</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">9000</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;App listening on port 9000.&#34;</span><span class="p">));</span>
</span></span></code></pre></div><p>While rest of the lines remain the same as earlier, <code>app.use(&quot;/&quot;, router);</code> will signify that the new route will be available at <code>/</code>. If you had typed <code>/blog</code> instead, we could have specified routes only applicable to a blog. For e.g. <code>/blog/post-1</code>, <code>/blog</code>, <code>/blog/post-2</code>, etc.</p>
<p>Routes by themselves can execute some code and send the response back to the caller. But, that&rsquo;s no joy - we need to display information in a structured manner on a page. Enter <code>views</code>.</p>
<h2 id="views-in-express">Views in Express</h2>
<p>Views can be simple HTML pages that display any information. In our example we use a templating language (<code>ejs</code>) to create HTML and include variables in the HTML. These variables are substituted at runtime by values from database, disk or from external API calls.</p>
<p>To use <code>ejs</code> we need to tell Express that. Change <code>app.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// setup
</span></span></span><span class="line"><span class="cl"><span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dotenv&#34;</span><span class="p">).</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s2">&#34;view engine&#34;</span><span class="p">,</span> <span class="s2">&#34;ejs&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="s2">&#34;public&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="nx">extended</span><span class="o">:</span> <span class="kc">false</span> <span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./routes/index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="nx">router</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">9000</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;App listening on port 9000.&#34;</span><span class="p">));</span>
</span></span></code></pre></div><p>Create a new view <code>hello.ejs</code> in <code>&lt;project_root&gt;/views/</code> folder. Add below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>hello world<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Change the <code>hello</code> route in <code>routes/index.js</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;hello&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>Visit <code>http://localhost:9000/hello</code> to see the <code>hello world</code> message.</p>
<p>So far you have seen how routes work, how to interact with database, and how to create views and display information. These are the only building blocks we need - let&rsquo;s put them together for our blog.</p>
<h2 id="understand-routes-for-a-blog">Understand routes for a Blog</h2>
<p>What exactly can you do with a blog?</p>
<ul>
<li>Display posts</li>
<li>View a specific post</li>
<li>Write a post</li>
<li>Update a post</li>
<li>Delete a post</li>
</ul>
<p>Each of these actions will have a specific route in Express. Let&rsquo;s start with displaying a list of posts.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;../data/db&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">slugify</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;slugify&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">marked</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;marked&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">domPurify</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dompurify&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">JSDOM</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;jsdom&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">purify</span> <span class="o">=</span> <span class="nx">domPurify</span><span class="p">(</span><span class="k">new</span> <span class="nx">JSDOM</span><span class="p">().</span><span class="nb">window</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// const results = await db.query(&#34;select * from posts&#34;);
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// res.send({ rows: results.rows });
</span></span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">orderBy</span><span class="p">(</span><span class="s2">&#34;created_at&#34;</span><span class="p">,</span> <span class="s2">&#34;desc&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/index&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">posts</span><span class="o">:</span> <span class="nx">posts</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>We are pointing two routes <code>/</code> (<code>http://localhost:9000</code>) and <code>/blog</code> (<code>http://localhost:9000/blog</code>) to two views <code>index</code> and <code>blog/index</code> respectively.</p>
<p>Let us add the two views.</p>
<p>Create a new view <code>views/index.ejs</code>, which will serve as the home page for the app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    Head section this is
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 1<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 2<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>Welcome to Bloggie<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>&#39;tis where magic happens.<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>Go to Blog!<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>(c) Bloggie Blog.<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a new view <code>views/blog/index.ejs</code> to display a list of posts.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    Head section this is
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 1<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 2<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>List of Posts<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 1<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 2<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 3<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>(c) Bloggie Blog.<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You can now visit the URLs <code>/</code> and <code>/blog</code> to see these views. You may have observed that we have repeated information in sections like <code>head</code>, <code>footer</code> etc. <code>ejs</code> provides a good way to reuse sections by creating them in one place and including them in any other views as required.</p>
<p>We can easily do that for our views. First create a reusable &ldquo;partial file&rdquo; called <code>views/partials/head.ejs</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My Super Blog<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a second partial for navigation <code>views/partials/nav.ejs</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">header</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-align: center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;site-title&#34;</span><span class="p">&gt;</span>My Super Blog<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>Home<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> | <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;</span>Blog<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> |
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://github.com/prashanth1k/bloggie&#34;</span><span class="p">&gt;</span>GitHub<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create another partial for footer <code>views/partials/footer.ejs</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">hr</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-align:center; color:grey; font-size: small;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  © 2020-Infinity My Super Blog
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We now include these partials in our views.</p>
<p>Our <code>index.ejs</code> will change to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>Welcome to Bloggie<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>&#39;tis where magic happens.<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>Go to Blog!<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;./partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The <code>&lt;%- %&gt;</code> tags allow you to include variables, values and functions. Here we use <code>include</code> statement to include another <code>ejs</code> file &ldquo;as is&rdquo; - meaning, the target <code>ejs</code> file will be copied/pasted in the parent &ldquo;in full&rdquo; at runtime.</p>
<p>The blog list page <code>blog/index.ejs</code> will change to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>List of Posts<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 1<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 2<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 3<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;./partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The end result will be the same as earlier.</p>
<p>Since we are on the topic of views and views are about displaying information in a beautiful way - let us also include some styles.</p>
<p>Change <code>views/partials/head.ejs</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span>
</span></span><span class="line"><span class="cl">  <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text/css&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/css/styles.css&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;preconnect&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://fonts.gstatic.com&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span>
</span></span><span class="line"><span class="cl">  <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;800&amp;display=swap&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My Super Blog<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span></code></pre></div><p><code>milligram.css</code> is a nice, classless styling library. It allows you to style your apps without adding any (or many) styling classes and has sensible defaults for standard HTML elements. We will include additional styling for our app in a new file called <code>/css/styles.css</code>. Check out the <a href="https://github.com/prashanth1k/bloggie">Github repo</a> for contents of <code>styles.css</code> - we will not be discussing any details here.</p>
<p>Pull in Open Sans Google fonts just because you can. You can use any font that you like.</p>
<h2 id="routes-for-your-blog-app">Routes for your Blog App</h2>
<p>Now that we have grasped the basics of routes and views, let us start adding routing logic for all possible transactions by changing <code>routes/index.js</code>.</p>
<h3 id="base-structure-of-routes">Base structure of routes</h3>
<p>The basic structure of routes remains as-is. We will add a DB reference to enable us to query or update database for specific route transactions.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;../data/db&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="display-a-list-of-posts">Display a list of posts</h3>
<p>Add route to show posts -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">orderBy</span><span class="p">(</span><span class="s2">&#34;created_at&#34;</span><span class="p">,</span> <span class="s2">&#34;desc&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/index&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">posts</span><span class="o">:</span> <span class="nx">posts</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>All we are doing here is to -</p>
<ul>
<li>get content from <code>posts</code> table in database <code>db.from(&quot;posts&quot;)</code> ordered by created date</li>
<li>render the view <code>blog/index</code>. Pass data from database to the view</li>
</ul>
<p>We have already seen how to use variable values in the view - we will see actual code in the next section.</p>
<h3 id="display-a-specific-post">Display a specific post</h3>
<p>Create a route/method to &ldquo;show&rdquo; a specific blog post.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/show&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>See the string <code>:id</code> in route url? This implies that <code>id</code> is a variable. For e.g. the URL can be <code>http://localhost:9000/blog/1</code> (id = 1), <code>http://localhost:9000/blog/42</code> (id = 42), and so on.</p>
<p>We query database for the specific id passed in the URL and, as was earlier, provide the data to the view.</p>
<p>While using <code>id</code> simply works, URLs with ids are not really user-friendly. Let us change it to include a URL-friendly version of our post title (called <code>slug</code>). Slug is a distinct column we created for the purpose, and we will use that column instead of <code>id</code>. For e.g. a post with title &ldquo;Hello World!&rdquo; can have the slug <code>hello-world</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/:slug&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">slug</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/show&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Let&rsquo;s do one more thing while we are on this topic. Let us allow user to type content in markdown. This is not a problem while saving the record since we save the entries as-is, but we should render markdown as formatted HTML when showing the blog post. We can do that using a library called <code>marked</code> and combining that with a package or two to sanitize the HTML (<code>purify</code> / <code>jsdom</code>).</p>
<p>Install package -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save marked dompurify marked jsdom
</span></span></code></pre></div><p>Include the libraries in our route code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">marked</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;marked&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">domPurify</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dompurify&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">JSDOM</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;jsdom&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">purify</span> <span class="o">=</span> <span class="nx">domPurify</span><span class="p">(</span><span class="k">new</span> <span class="nx">JSDOM</span><span class="p">().</span><span class="nb">window</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/:slug&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">slug</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">post</span><span class="p">.</span><span class="nx">content</span> <span class="o">=</span> <span class="nx">post</span><span class="p">.</span><span class="nx">content</span> <span class="o">?</span> <span class="nx">purify</span><span class="p">.</span><span class="nx">sanitize</span><span class="p">(</span><span class="nx">marked</span><span class="p">(</span><span class="nx">post</span><span class="p">.</span><span class="nx">content</span><span class="p">))</span> <span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/show&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="create-a-new-post">Create a new post</h3>
<p>We will create a route/view to display fields of a post and allow user to create new post.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/new&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="p">{}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p><code>post: {}</code> passes an empty object called <code>post</code> to the view. We will tie the fields in the view to attributes of this object. We use an empty object here rather than not passing anything at all since we may want to change this in the future to default the values of few fields on the view. You can safely ignore this for now.</p>
<h3 id="save-a-post">Save a post</h3>
<p>Create a route to save a new post by using a <code>POST</code> transaction.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The function used in this route will perform below tasks -</p>
<ul>
<li>gets data passed in <code>req</code>. In our case a view passes this data along after the user enters data and submits the form</li>
<li>inserts a record in <code>posts</code> table and populates values</li>
<li>redirects to the URL <code>/blog/&lt;some_id&gt;</code>. We have created the route for this previously - that route will fetch record with this <code>id</code> and call the &ldquo;show&rdquo; view to display post details</li>
</ul>
<p>Again, using id just works. But this is not quite what we want. Let us bring in <code>slug</code> here - but we want to solve the problem of converting title automatically to a slug. We do that using a package called <code>slugify</code>.</p>
<p>First, install <code>slugify</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save slugify
</span></span></code></pre></div><p>Change the above logic -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">strict</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The logic here is simple and straight forward. But, what happens if you are saving an updated record? We would then need to define another route and specify a different service. To keep things simple, let us combine save function for both new and updated records -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">strict</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">update</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">slug</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="edit-a-post">Edit a post</h3>
<p>Editing a post includes two transactions-</p>
<ol>
<li>Query for a specific post (and hand it over to view)</li>
<li>(Once user is done and clicks <code>Save</code>) Collect details updated by user and hand it over to a route / service to save the changes</li>
</ol>
<p>We will achieve the first part through the URL <code>http://localhost:9000/blog/edit/&lt;post_slug&gt;</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/edit/:slug&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">slug</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>While we could use different routes/logic to save new posts and to save updated posts, here we keep things simple. We will reuse <code>router.post(&quot;/blog&quot;, async (req, res) =&gt; {}</code> function as described in the previous section to save updates.</p>
<h2 id="more-views-for-blog-app">More Views for Blog App</h2>
<p>We are done with most of the routes. Let us create views to go along with them. Create a folder <code>views/blog</code> to store all <code>blog</code> related views in one place. Let&rsquo;s start with the views.</p>
<h3 id="display-a-list-of-posts-1">Display a list of posts</h3>
<p>Create a new view <code>views/blog/index.ejs</code> to show list of posts.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;postlist-nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog/new&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>New Post<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">&lt;</span>% posts.forEach(post =&gt; { %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">aside</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;postlist-title&#34;</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.title %&gt;<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            📅 <span class="err">&lt;</span>%= post.created_at.toISOString().substring(0,10) %&gt; | 📁<span class="err">&lt;</span>%=
</span></span><span class="line"><span class="cl">            post.tags %&gt;
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.content.substring(0,200) + &#39;...&#39; %&gt;<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">aside</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog/&lt;%= post.slug %&gt;&#34;</span><span class="p">&gt;</span>Read More<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">&lt;</span>% }); %&gt;
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We receive posts from the route file and display records here. A few more interesting observations -</p>
<ul>
<li>We can use expressions in our EJS templates. e.g. <code>&lt;%= post.content.substring(0,200) + '...' %&gt;</code></li>
<li>We can use loops to display repeated sections - <code>&lt;% posts.forEach(post =&gt; { %&gt;</code>. <code>&lt;%</code> will just perform calculations, while <code>&lt;%=</code> will print out the result</li>
<li>You can use expressions in HTML tags or attributes</li>
<li>Note that we pass arguments to the route with the link <code>&lt;a href=&quot;/blog/&lt;%= post.slug %&gt;&quot;&gt;Read More&lt;/a&gt;</code></li>
</ul>
<p>Navigate to <code>https://localhost:9000/blog/</code> to see this view.</p>
<h3 id="display-a-specific-post-1">Display a specific post</h3>
<p>Create a new view <code>views/blog/show.ejs</code> and include below code.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-align: end;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog/edit/&lt;%= post.slug %&gt;&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>Edit<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-title&#34;</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.title %&gt;<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          📅 <span class="err">&lt;</span>%= post.created_at.toISOString().substring(0,10) %&gt; | 📁<span class="err">&lt;</span>%=
</span></span><span class="line"><span class="cl">          post.tags %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span><span class="err">&lt;</span>%- post.content %&gt;<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This is very similar to what wee had earlier, but we just show one post rather than a bunch of posts.</p>
<p>The only additional thing to note is the redirection to <code>edit</code> view when user clicks on the edit post button.</p>
<h3 id="create-a-new-post-1">Create a new post</h3>
<p>Create new view <code>views/blog/new.ejs</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="err">&lt;</span>%- include(&#34;_form_default&#34;) %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We have included a <code>_form_default.ejs</code> here instead of directly filling in the form fields for creating a new post. This is to encourage reuse of the form for both <code>new</code> and <code>edit</code> post functions.</p>
<p>Also take note of <code>&lt;form action=&quot;/blog&quot; method=&quot;POST&quot;&gt;</code> which redirects user to a route <code>/blog</code> with a method <code>POST</code> on submission of the form. The form is submitted at the click of <code>Save</code> button.</p>
<p>Create a new partial view <code>views/blog/_form_default.ejs</code> to house all controls of the form -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;form-group&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;postlist-header&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#39;text&#39;</span> <span class="na">label</span><span class="o">=</span><span class="s">&#34;tags&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&lt;%= post.title %&gt;&#34;</span>  <span class="na">required</span><span class="p">&gt;&lt;/</span><span class="nt">input</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Tags 📁<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tags&#34;</span> <span class="na">name </span><span class="o">=</span> <span class="s">&#34;tags&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">label</span><span class="o">=</span><span class="s">&#34;tags&#34;</span> <span class="na">required</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&lt;%= post.tags %&gt;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>Content<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">textarea</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;30&#34;</span> <span class="na">rows</span><span class="o">=</span><span class="s">&#34;20&#34;</span> <span class="na">required</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.content %&gt;<span class="p">&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;id&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;id&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;hidden&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&lt;%= post.id %&gt;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;form-group&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span>Save<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The form is a standard HTML form except the values of the fields - they are derived from the query and passed across to EJS as a parameter.</p>
<h3 id="save-a-post-1">Save a post</h3>
<p>Take action when the data is posted to <code>/blog</code> route. We do all the required operations in the route file itself to keep things simple. In real world you may want to just keep routing logic here and hive everything else to separate JS files (&amp; call them &ldquo;services&rdquo;).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">strict</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">update</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">slug</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The actual DB save is self-explanatory and simple - thanks to <code>knex</code>. We perform an insert or update operation depending on whether <code>id</code> value already exists in the <code>post</code> object.</p>
<p>Once the record is saved, we show the saved post with <code>res.redirect(</code>/blog/${slug}<code>);</code></p>
<h3 id="editing-a-post">Editing a post</h3>
<p>We used a route <code>/blog/edit/:id</code> to trigger edit logic. The route queries the DB and passes the specific post details along.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="err">&lt;</span>%- include(&#34;_form_default&#34;) %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We will reuse the route <code>/blog</code> with method <code>POST</code> to save record - you will see this in the submit action <code>&lt;form action=&quot;/blog&quot; method=&quot;POST&quot;&gt;</code>.</p>
<h2 id="finis">Finis</h2>
<p>So, there you have it - a beautiful looking blog app of your own! You can create new posts, display a list of posts, view single post and even edit it :). Want more? Comment and let me know!</p>
<p>See the complete code on the <a href="https://github.com/prashanth1k/bloggie">Github repo</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Shorten URL with Express and AlpineJS</title>
      <link>https://techformist.com/shorten-url-app-express-alpinejs/</link>
      <pubDate>Wed, 01 Jul 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/shorten-url-app-express-alpinejs/</guid>
      <description>&lt;p&gt;In this post let us see how we can leverage the power of Express with a sprinkling of Alpine JS to create a quick URL shortener application.&lt;/p&gt;
&lt;h2 id=&#34;but-why&#34;&gt;But, why?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://expressjs.com/&#34;&gt;Express&lt;/a&gt; is the most popular server-side framework and my &amp;ldquo;go to&amp;rdquo; choice for creating anything really quick. Building a front-end for Express is as easy as using handlebars (or anything really) that goes in HTML served by Express. But that lacks a &amp;ldquo;nice&amp;rdquo; user experience.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In this post let us see how we can leverage the power of Express with a sprinkling of Alpine JS to create a quick URL shortener application.</p>
<h2 id="but-why">But, why?</h2>
<p><a href="https://expressjs.com/">Express</a> is the most popular server-side framework and my &ldquo;go to&rdquo; choice for creating anything really quick. Building a front-end for Express is as easy as using handlebars (or anything really) that goes in HTML served by Express. But that lacks a &ldquo;nice&rdquo; user experience.</p>
<p><a href="https://github.com/alpinejs/alpine">AlpineJS</a> is a small and sweet framework that will go places. It follows Vue in many respects (and tries to achieve parity in a lot of respects), but does not want to be a full-scaled framework. Rather, it sits happily with other code to provide user interactivity to your front-end.</p>
<p>Depending on what you are set to do, AlpineJS can be a good choice for your back-end application.</p>
<h2 id="use-case-shorten-url">Use Case: Shorten URL</h2>
<p>The premise is simple.</p>
<ol>
<li>User supplies URL (e.g. <code>http://twitter.com/techformist</code>)</li>
<li>We shorten it and give it back to user (e.g. <code>https://go.co/tf</code>, assuming <code>go.co</code> is our domain)</li>
<li>Anyone can use the short URL. The request just bounces off our server to navigate to the longer web address</li>
</ol>
<p>For simplicity we will ignore any authentication requirements.</p>
<p>We will use ExpressJS as the backend because that is one of the quicker and nicer frameworks to work with. We will use SQLite as the database.</p>
<h2 id="create-a-basic-express-app-with-sqlite-db">Create a Basic Express App with SQLite DB</h2>
<p>We will start building with some basic code. No generators, no fluff.</p>
<p>Create a new folder for your project and initialise using <code>npm</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">mkdir</span> shortu
</span></span><span class="line"><span class="cl"><span class="k">cd</span> shortu
</span></span><span class="line"><span class="cl">npm init -y
</span></span></code></pre></div><p><code>npm init</code> will create <code>package.json</code> in your project folder. Edit the file to include scripts to run your application.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">//  ...
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;scripts&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;run&#34;</span><span class="p">:</span> <span class="s2">&#34;node server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;dev&#34;</span><span class="p">:</span> <span class="s2">&#34;nodemon server&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Install <code>express</code>, <code>sqlite3</code> and a few useful libraries for security.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save express express cors helmet sqlite3 yup
</span></span></code></pre></div><p>Install <code>nodemon</code> so that our express application gets restarted automatically every time there is a change. This is useful during development.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save-dev nodemon
</span></span></code></pre></div><p>Create a new file <code>server.js</code> - this will be our main Express file. Let us bring in <code>express</code> and friends.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">cors</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;cors&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">helmet</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;helmet&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">yup</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;yup&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>Include logic to initialise database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">sqlite3</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;sqlite3&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sqlite3</span><span class="p">.</span><span class="nx">Database</span><span class="p">(</span><span class="s2">&#34;./db/data.sqlite&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="k">throw</span> <span class="nx">err</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Connected to the SQLite database.&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">db</span><span class="p">.</span><span class="nx">run</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;CREATE TABLE IF NOT EXISTS urls (slug VARCHAR(100) PRIMARY KEY, url VARCHAR(255), clicks INTEGER)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nx">res</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>SQLite is just a file at heart (which database isn&rsquo;t?). The above logic checks for a file called <code>db/data.sqlite</code>. If the file does not exist, SQLite takes care of creating a new file. <code>db.run</code> is used to run a SQL statement.</p>
<p>We will execute an SQL to create a table called <code>urls</code> if it doesn&rsquo;t already exist. There are three columns in this table -</p>
<ul>
<li><code>url</code> - long form URL supplied by user</li>
<li><code>slug</code> - key part of short-form URL. Can be supplied by user or we generate one</li>
<li><code>clicks</code> - no. of clicks on the short URL</li>
</ul>
<p>Initialise express.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// middleware
</span></span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">helmet</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">cors</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">json</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="s2">&#34;./public&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// listener
</span></span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Listening on port 3000.&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Include a test statement to show a message for a request.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/*&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span> <span class="nx">message</span><span class="o">:</span> <span class="s2">&#34;Hello, world&#34;</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>.. and an error function to process any errors anywhere.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// error handling
</span></span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">((</span><span class="nx">err</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">json</span><span class="p">({</span> <span class="nx">message</span><span class="o">:</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The basic Express application is now ready!</p>
<p>You can run the application using -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">npm</span> <span class="nx">run</span> <span class="nx">dev</span>
</span></span></code></pre></div><p>This should print a message - <code>Listening on port 3000.</code></p>
<p>Send a <code>POST</code> request using your <a href="https://insomnia.rest/">favourite API testing tool</a> to see <code>&quot;Hello, world&quot;</code> message in response.</p>
<h2 id="define-apis-in-your-express-application">Define APIs in your Express Application</h2>
<p>Before we go ahead with the API request/response, let use define a valid structure for the expected input.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// schema defn.
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">schema</span> <span class="o">=</span> <span class="nx">yup</span><span class="p">.</span><span class="nx">object</span><span class="p">().</span><span class="nx">shape</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">url</span><span class="o">:</span> <span class="nx">yup</span><span class="p">.</span><span class="nx">string</span><span class="p">().</span><span class="nx">url</span><span class="p">().</span><span class="nx">required</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">slug</span><span class="o">:</span> <span class="nx">yup</span><span class="p">.</span><span class="nx">string</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>We will have three services -</p>
<ol>
<li>Create new &ldquo;short URL&rdquo;</li>
<li>Navigate user to the long URL when a valid short URL is provided</li>
<li>List existing short URLs</li>
</ol>
<p>This is also a good time to remember that we need to generate a random string if user does not provide the &ldquo;slug&rdquo; for the short URL. This can be done in a number of ways.</p>
<p>We will use a package called <code>crypto-random-string</code>. Let us install the package.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save crypto-random-string
</span></span></code></pre></div><p>Alternatively, you can use -</p>
<ul>
<li><a href="https://www.npmjs.com/package/nanoid">nanoid</a></li>
<li><a href="https://www.npmjs.com/package/randomstring">randomstring</a></li>
</ul>
<p>Let us start coding in the services.</p>
<h3 id="create-new-short-url">Create new &ldquo;short URL&rdquo;</h3>
<p>Create a new short URL for the user-provided URL.</p>
<ol>
<li>The generated short URL will be the combination of our domain (where the Express application is running) + a short slug.</li>
<li>Slug is provided in request. It is optional, generate a URL-safe slug if not provided</li>
<li>Store long form URL and the slug in the database</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/new&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// get url and slug from input
</span></span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="p">{</span> <span class="nx">url</span><span class="p">,</span> <span class="nx">slug</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;req.body: &#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">await</span> <span class="nx">schema</span><span class="p">.</span><span class="nx">validate</span><span class="p">({</span> <span class="nx">url</span><span class="p">,</span> <span class="nx">slug</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">slug</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// generate slug if not provided by user
</span></span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">cryptoRandomString</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;crypto-random-string&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">slug</span> <span class="o">=</span> <span class="nx">cryptoRandomString</span><span class="p">({</span> <span class="nx">length</span><span class="o">:</span> <span class="mi">10</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;url-safe&#34;</span> <span class="p">}).</span><span class="nx">toLowerCase</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// insert everything in DB
</span></span></span><span class="line"><span class="cl">    <span class="nx">db</span><span class="p">.</span><span class="nx">exec</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="sb">`INSERT INTO urls(url, slug , clicks) VALUES(&#39;</span><span class="si">${</span><span class="nx">url</span><span class="si">}</span><span class="sb">&#39;, &#39;</span><span class="si">${</span><span class="nx">slug</span><span class="si">}</span><span class="sb">&#39;, 0)`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;err: &#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// response message has the short URL
</span></span></span><span class="line"><span class="cl">        <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">shorturl</span><span class="o">:</span> <span class="sb">`http://</span><span class="si">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">host</span><span class="si">}</span><span class="sb">/</span><span class="si">${</span><span class="nx">slug</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">url</span><span class="o">:</span> <span class="nx">url</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">next</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>It is time to test this out!</p>
<p>Send a request to <code>http://localhost:3000/new</code> like so -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://google.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;slug&#34;</span><span class="p">:</span> <span class="s2">&#34;ro0wgfvwxg&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You should receive this beautiful response -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://google.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;slug&#34;</span><span class="p">:</span> <span class="s2">&#34;ro0wgfvwxg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;shorturl&#34;</span><span class="p">:</span> <span class="s2">&#34;http://localhost:3000/ro0wgfvwxg&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Your short URL generation is ready, onwards to doing something with this request.</p>
<h3 id="navigate-user-to-long-url">Navigate user to long URL</h3>
<p>With the previous service the user received this short URL <code>http://localhost:3000/ro0wgfvwxg</code>, which can now be happily shared by her to thousands of people.</p>
<p>When these people use the URL in a browser, the request is sent to our server. This can be fulfilled by a service that will fetch the long-form URL from the given short URL, and automatically navigate users to the correct destination.</p>
<p>This is easier than it looks.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// id = slug. e.g. `ro0wgfvwxg`
</span></span></span><span class="line"><span class="cl">  <span class="c1">// fetch data from DB
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">db</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="sb">`SELECT * FROM urls where slug=&#39;</span><span class="si">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">&#39;`</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// navigate user to the right URL
</span></span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The above code should do the trick. But, let&rsquo;s improve that a bit more -</p>
<ul>
<li>add error handling - navigate user to an error page if slug is not found</li>
<li>add logic to count number of clicks. Each time anyone uses the URL, the number of clicks will be incremented</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">db</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="sb">`SELECT * FROM urls where slug=&#39;</span><span class="si">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">&#39;`</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">data</span><span class="p">)</span> <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/?error=</span><span class="si">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb"> not found!`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// add clicks
</span></span></span><span class="line"><span class="cl">    <span class="nx">db</span><span class="p">.</span><span class="nx">exec</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="sb">`UPDATE urls SET clicks = clicks + 1 WHERE slug=&#39;</span><span class="si">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">&#39;`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Now, try navigating to <code>https://localhost:/ro0wgfvwxg</code> in the browser. You should be navigated to the correct URL <code>http://google.com</code>.</p>
<h3 id="list-urls">List URLs</h3>
<p>Let us code the last of the services - list all URLs in the database.</p>
<p>This service is similar to the previous one, except that we run a simpler query to fetch all URLs and return them to the caller.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/list&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">db</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span><span class="sb">`SELECT * FROM urls`</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="nx">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">data</span><span class="o">:</span> <span class="nx">data</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Try it! A request to <code>https://localhost:3000/list</code> should return all the URLs from the database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;slug&#34;</span><span class="p">:</span> <span class="s2">&#34;ro0wgfvwxg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://google.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;clicks&#34;</span><span class="p">:</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;slug&#34;</span><span class="p">:</span> <span class="s2">&#34;whphznmvcf&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://bing.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;clicks&#34;</span><span class="p">:</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Your backend application is now fully ready to take on the world.</p>
<h2 id="front-end-for-shorten-url-application">Front-end for Shorten URL Application</h2>
<p>Create a simple HTML file <code>index.html</code> in the project root, which will contain the whole of our frontend. Include AlpineJS from CDN.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=400px, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>Shortu<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">script</span>
</span></span><span class="line"><span class="cl">      <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">defer</span>
</span></span><span class="line"><span class="cl">    <span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    Frontend Does Not Rock
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Let us code some CSS since no one likes to see default styling. Since I am too lazy to do the complete styling by myself (capability aside), I will use a simple CSS framework called &ldquo;MVP.css&rdquo;.</p>
<p>Include MVP.css and a custom CSS (for minimal style changes) in the HTML head.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/mvp.css&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;./assets/custom.css&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>Create folders in the project root.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">mkdir</span> public <span class="p">&amp;&amp;</span> <span class="k">cd</span> public <span class="p">&amp;&amp;</span> <span class="k">mkdir</span> assets
</span></span><span class="line"><span class="cl"><span class="k">cd</span> assets
</span></span><span class="line"><span class="cl">touch custom.css
</span></span></code></pre></div><p>We can use powerful functions to bind HTML elements to backend. Let us create a form and the necessary objects that will act as the container for all functionality.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span> <span class="na">x-data</span><span class="o">=</span><span class="s">&#34;process()&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h1</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Shortu URL Shortener<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    Input the long URL, hit &#34;Shorten&#34; and see magic happen.
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">form</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;input-group&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Provide the long URL&#34;</span> <span class="na">x-model</span><span class="o">=</span><span class="s">&#34;url&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">      <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">class</span><span class="o">=</span><span class="s">&#34;form-control&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Desired short url phrase (optional)&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">x-model</span><span class="o">=</span><span class="s">&#34;slug&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">process</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">url</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">slug</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Note that -</p>
<ul>
<li><code>process()</code> will provide the infrastructure for AlpineJS. You can define JS variables, functions and more within <code>process</code> function</li>
<li><code>x-model</code> binds the HTML element to the backend variable (for e.g. <code>url</code>). This is similar to <code>v-model</code> in Vue</li>
</ul>
<p>Express serves the HTML file by default when we navigate to <code>https://localhost:3000/</code>. Navigate to this URL in the browser to see your application in action.</p>
<p>Let us add functionality to allow user to send request to Express and see results.</p>
<p>Add a button that sends data to backend Express, and elements to show results (or error). Input below code before the ending <code>&lt;/form&gt;</code> element.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">button</span> <span class="na">x-on:click</span><span class="err">.</span><span class="na">prevent</span><span class="o">=</span><span class="s">&#34;shortenURL()&#34;</span><span class="p">&gt;</span>Submit<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">x-show</span><span class="o">=</span><span class="s">&#34;error&#34;</span> <span class="na">x-on:click</span><span class="o">=</span><span class="s">&#34; error = &#39;&#39;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">span</span> <span class="na">x-text</span><span class="o">=</span><span class="s">&#34;error&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>❌
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;results&#34;</span> <span class="na">x-show</span><span class="o">=</span><span class="s">&#34;data[&#39;shorturl&#39;]&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;results&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;label&#34;</span><span class="p">&gt;</span>Your short URL:<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: inline-block;&#34;</span> <span class="na">x-text</span><span class="o">=</span><span class="s">&#34;data.shorturl&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Add the corresponding functions and variables in <code>process</code>.</p>
<ul>
<li><code>data</code> to store the response URL list and <code>error</code> to store error</li>
<li><code>shortenURL</code> - a function that invokes our <code>new</code> service to shorten a given URL</li>
</ul>
<p>The complete <code>&lt;script&gt;</code> element is below -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kd">function</span> <span class="nx">process</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">error</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">data</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">url</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">slug</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">shortenURL</span><span class="o">:</span> <span class="kr">async</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;this.url&#34;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="sb">`/new/`</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;POST&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="nx">headers</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="nx">Accept</span><span class="o">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="s2">&#34;Content-Type&#34;</span><span class="o">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">url</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">url</span><span class="p">,</span> <span class="nx">slug</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">slug</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">          <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">resJson</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">result</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;resJson: &#34;</span><span class="p">,</span> <span class="nx">resJson</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="k">if</span> <span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;result.ok: &#34;</span><span class="p">,</span> <span class="nx">result</span><span class="p">.</span><span class="nx">ok</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">data</span> <span class="o">=</span> <span class="nx">resJson</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">error</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;in error&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">data</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">error</span> <span class="o">=</span> <span class="nx">resJson</span><span class="p">[</span><span class="s2">&#34;message&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;data: &#34;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;error: &#34;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">error</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;error&#34;</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">error</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Voila, your application is ready just like that.</p>
<p><img loading="lazy" src="/2020/url-shortener-express-alpinejs.gif" type="" alt="url-shortener-express-alpinejs"  /></p>
<p>Complete code is at <a href="https://github.com/techformist/shortu">this Github repo</a>.</p>
<h2 id="the-end">The End</h2>
<p>Building applications with Express is fun, and libraries like Alpine make the user experience fun too. I have to say - I am quite smitten this smart library.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
