<?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>NodeJS on Techformist</title>
    <link>https://techformist.com/categories/nodejs/</link>
    <description>Recent content in NodeJS 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, 16 Dec 2020 06:30:00 +0000</lastBuildDate><atom:link href="https://techformist.com/categories/nodejs/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Build a Simple News App using Adonis v5</title>
      <link>https://techformist.com/create-simple-news-app-adonisjs/</link>
      <pubDate>Wed, 16 Dec 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-simple-news-app-adonisjs/</guid>
      <description>&lt;p&gt;AdonisJS has been my framework of choice to get stuff done quickly. The framework has taken a turn for the good with more frequent updates to its latest version - v5, which features Typescript, the same trusted MVC framework, and &amp;ldquo;everything &amp;amp; kitchen sink&amp;rdquo; approach that is quite effective to easily build apps.&lt;/p&gt;
&lt;p&gt;In this post we will create a simple news website using AdonisJS. The focus will be on -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>AdonisJS has been my framework of choice to get stuff done quickly. The framework has taken a turn for the good with more frequent updates to its latest version - v5, which features Typescript, the same trusted MVC framework, and &ldquo;everything &amp; kitchen sink&rdquo; approach that is quite effective to easily build apps.</p>
<p>In this post we will create a simple news website using AdonisJS. The focus will be on -</p>
<ol>
<li>Creating a site that is publisher-friendly</li>
<li>Login/auth and publish functions</li>
<li>Support user authentication for creating news articles</li>
<li>Basic styling with a classless framework - we will choose <a href="https://milligram.io">milligram</a> at this time</li>
</ol>
<p>Here&rsquo;s how the app will look like -</p>
<p><img loading="lazy" src="/2020/adonisjs-sample-news-app.gif" type="" alt="adonisjs-sample-news-app"  /></p>
<p>Let&rsquo;s get rocking.</p>
<h2 id="why-adonisjs">Why AdonisJS?</h2>
<p>While there are no dearth of frameworks in NodeJS, you may want to consider AdonisJS -</p>
<ol>
<li>Be productive with many decisions made for you. Start creating your apps rather than spending time on tying up various libraries and packages</li>
<li>Create structured, methodical and easy-to-understand code</li>
<li>Use a view layer that can enable you to build something quickly. Or, enable APIs that can be consumed by your SPA or mobile apps</li>
</ol>
<p>There is no dearth of frameworks using NodeJS, and I am a super fan of Node because of that. But AdonisJS has held its own with its developer-friendly approach, similarity with Laravel (which is a super-productive way to do things), and, of course, with the power of Javascript/Typescript.</p>
<h2 id="get-started-installation">Get Started: Installation</h2>
<p>Ensure you have NodeJS installed on your computer. <a href="https://nodejs.org/en/">Download Node</a> and <a href="https://nodejs.dev/learn/how-to-install-nodejs">follow installation instructions</a> if you are into such type of thing.</p>
<p>Although not strictly required, I recommend you choose a nice database to go along with your app. You can choose from Postgres, MySQL, Oracle, or SQLite. Take help from our dear friend, Google, to find out how to install DBs. Or, just download <a href="https://laragon.org/">Laragon</a> that does all the hard work, and expects you to just start the darn thing.</p>
<p>We are now ready to start creating the app. Create your Adonis app with a simple command.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm init adonis-ts-app newsie
</span></span></code></pre></div><p>The command creates a folder called &rsquo;newsie&rsquo; and takes you through a few options.</p>
<p><img loading="lazy" src="/2020/create-new-app-adonisjs.jpg" type="" alt="create-new-app-adonisjs"  /></p>
<p>We will create a <code>Web Application</code> for the news site. The other option is to choose an API, which can be useful to build a single page application (among other things). Choose defaults for other options, or roll a dice to choose values for you. The wizard only asks your input to use ESLint (<code>y</code>) and, possibly, Prettier at this time.</p>
<p>Navigate to the project folder and open the folder in VSCode.</p>
<p>Next, we install a package to enable connecting to a database.</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 @adonisjs/lucid@alpha
</span></span></code></pre></div><p>Invoke the configurator.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace invoke @adonisjs/lucid
</span></span></code></pre></div><p>The command will allow you to choose your database, sets up a few essentials, and provide instructions on changing configuration. Follow the instructions to update <code>env.ts</code> file - add below lines to the file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">rules</span><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 class="nx">PG_HOST</span>: <span class="kt">Env.schema.string</span><span class="p">({</span> <span class="nx">format</span><span class="o">:</span> <span class="s2">&#34;host&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_PORT</span>: <span class="kt">Env.schema.number</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_USER</span>: <span class="kt">Env.schema.string</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_PASSWORD</span>: <span class="kt">Env.schema.string.optional</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_DB_NAME</span>: <span class="kt">Env.schema.string</span><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 class="p">});</span>
</span></span></code></pre></div><p>Open <code>.env</code> file in your project folder and change below lines (varies depending on your options - I chose Postgres).</p>
<pre tabindex="0"><code>DB_CONNECTION=pg
PG_HOST=localhost
PG_PORT=5432
PG_USER=postgres
PG_PASSWORD=
PG_DB_NAME=newsie
</code></pre><p>The above configuration tells Adonis to connect to Postgres DB called <code>newsie</code> running on localhost port 5432, using the user <code>postgres</code>.</p>
<p>Create a new database called <code>newsie</code> in your database server. You can use a client like HeidiSQL or use an application that is bundled with your database (e.g. pgAdmin4 that comes with Postgres).</p>
<p><img loading="lazy" src="/2020/new-db-postgres.jpg" type="" alt="new-db-postgres"  /></p>
<p>Start your app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace serve --watch
</span></span></code></pre></div><p>The <code>--watch</code> flag watches for any changes in the project and automatically restarts Adonis server. You can now point your browser to and see the below glorious page.</p>
<p><img loading="lazy" src="/2020/adonis-start-page.jpg" type="" alt="adonis-start-page"  /></p>
<p>We now move on to developing the app.</p>
<h2 id="first-steps-develop-article-functionality">First Steps: Develop Article Functionality</h2>
<p>AdonisJS is a MVC framework. That means that our application uses a pattern that consists of three main logical layers -</p>
<ol>
<li>A model layer that takes care of all things database. Create your data structure, define relationships and so forth</li>
<li>A controller layer that allows you to create logic to write and retrieve data through the model layer</li>
<li>A view layer that takes care of presenting data to the user</li>
</ol>
<p>While this may sound too complex in the beginning, it&rsquo;s really making things easier (and standardized) for building real-world applications.</p>
<blockquote>
<p>Sidenote: There are arguably better, simplified architectures available today for building apps. MVC is still my go-to pattern since I find it easier to understand, can provide guidance and training to others to get started quickly, and there is a structure to everything in complex applications.</p>
</blockquote>
<h3 id="create-article-model">Create Article Model</h3>
<p>Let us add a component to store and allow interactions with articles, which is aptly called <code>Article</code>. We can create the model, controller and what is called a &ldquo;migration file&rdquo; in one go.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"> node ace make model Article -cm
</span></span></code></pre></div><p>The command will do three things -</p>
<ol>
<li>Create a model called <code>Article.ts</code></li>
<li>Create an associated controller called <code>ArticlesController.ts</code> in <code>app\Controllers\Http\</code> folder</li>
<li>Create <code>&lt;a_wierd_number&gt;__articles.ts</code> migration file in <code>database\migrations\</code> folder. We can use this migration file to create tables in the database. It is simpler this way since we will be adding new fields, migrating from our dev to production environment, etc. and having a file is easier to manage than using database migration tools</li>
</ol>
<p>Yes, the names of model, controller and the table created through the migration file is similar. Yes, you can change that behaviour though I don&rsquo;t know why you would do that.</p>
<p>Open the migration file and add a few fields.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">BaseSchema</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Lucid/Schema&#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">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">Articles</span> <span class="kr">extends</span> <span class="nx">BaseSchema</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">protected</span> <span class="nx">tableName</span> <span class="o">=</span> <span class="s2">&#34;articles&#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">public</span> <span class="kr">async</span> <span class="nx">up() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</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="k">this</span><span class="p">.</span><span class="nx">tableName</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</span><span class="p">)</span> <span class="o">=&gt;</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 class="s2">&#34;id&#34;</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">timestamps</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;title&#34;</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></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">(</span><span class="s2">&#34;publish_date&#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></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">down() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</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="k">this</span><span class="p">.</span><span class="nx">tableName</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 first two lines for <code>increments</code> and <code>timestamps</code> already existed in the file - they signify to the app that we will use a unique <code>id</code> field that is auto-incremented, and we will also use a <code>created_at</code> and <code>updated_at</code> fields that track created and modified dates. We add a couple of more fields and save the file.</p>
<p>Run the migration.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace migration:run
</span></span></code></pre></div><p>You will find a new table in your database with the specified fields.</p>
<p><img loading="lazy" src="/2020/adonis-db-table-created.jpg" type="" alt="adonis-db-table-created"  /></p>
<p>So far we created columns in a table, but the application wouldn&rsquo;t know what to do with them unless we change the model.</p>
<p>Edit <code>app/Models/Article.ts</code> to add more fields.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><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="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="nx">title</span>:<span class="kt">String</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="nx">content</span>:<span class="kt">String</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@column</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="nx">publishDate</span>: <span class="kt">DateTime</span>
</span></span></code></pre></div><h3 id="create-article-controller">Create Article Controller</h3>
<p>You can display a static page without data without any help from controller. But, a real-world app contains data, needs some business logic to be applied, security rules to be enforced and so on. Controller is the place to do all this.</p>
<p>We previously generated the controller file for Article while creating the model. Open <code>app/Controllers/ArticleController.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">HttpContextContract</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Core/HttpContext&#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">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">ArticlesController</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">create</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">store</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">show</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">edit</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">update</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">destroy</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</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>The file consists of a bunch of functions to facilitate all possible data operations. This controller can be reached through user (or app) actions.</p>
<p>The <code>start/routes.ts</code> file outlines the various resource operations that your Adonis app supports. Let us add a line to inform Adonis of our controller.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><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="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/articles&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticleController.index&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>In plain English: whenever someone tries to go to <code>&lt;app&gt;/articles</code>, invoke <code>index</code> function in <code>ArticleController</code>.</p>
<p>Change <code>index</code> function to return something.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s1">&#39;This is article.&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Point your browser to <code>http://localhost:3333/articles/</code> to see your message. Of course, we can do much more with controllers. Let us retrieve what we have in our <code>articles</code> table and try to show the contents.</p>
<p>Change <code>index</code> function to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">articles</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Article</span><span class="p">.</span><span class="nx">all</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">articles</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div><p>You will see more of these statements in a short while, but here&rsquo;s a rundown -</p>
<ol>
<li>Get all articles through the <code>Article</code> model</li>
<li>Return articles</li>
</ol>
<p>That&rsquo;s about it. If you go to <code>http://localhost:3333/articles/</code>, you will now see a grand <code>[]</code> as the output. It is an empty array since we don&rsquo;t have any records in the table. At this stage, you could create a few records directly in the table and see those records in the browser, or just wait for the next steps to start creating articles through the app.</p>
<h3 id="create-article-view">Create Article View</h3>
<p>Let us now turn focus to display the article through a view. Inspect <code>resources/view/welcome.edge</code>, which is a simple view file. Adonis views use <code>edge</code> templating language - we will see more of it soon.</p>
<p>You would have observed previously that <code>http://localhost:3333</code> in the browser opens up the <code>welcome</code> view. This is done through <code>start/routes.ts</code> file, specifically with the below line.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">).</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;welcome&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>This tells the application to serve a page <code>welcome</code> that will be sent to the browser when user accesses the root page.</p>
<p>Just for fun, create a new file in the same folder <code>resources/view/hello.edge</code>.</p>
<pre tabindex="0"><code>hello world
</code></pre><p>Add a different route to the <code>start/routes.ts</code> file.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</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></code></pre></div><p>Navigate to <code>http://localhost:3333/hello</code> to see your new page. It&rsquo;s as simple as that.</p>
<p>In the previous section, you had seen that we had invoked the <code>ArticleController.index()</code> method to return something to the view. The difference?</p>
<ul>
<li>Controller can retrieve data and pass it back to view</li>
<li>A view can simply show content - data, images or any HTML that you write therein</li>
<li>Data returned by controller is not directly displayed on the browser. You will pass it along to the view layer to make sense out of that data and display the beautified, organized content to users</li>
</ul>
<p>Let us improve our display a bit.</p>
<p>First, we will take a decision to show articles on the front page. So, let us change <code>welcome.edge</code>. Change the body section 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">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">main</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">h1</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Welcome to newsie!<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">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle&#34;</span><span class="p">&gt;</span>Positive news across the world.<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">      @!section(&#34;page&#34;)
</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">main</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>Create a new view <code>resources/views/articles/index.edge</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="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;welcome&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @each(article in articles)
</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>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>{{ article.title }}<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">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  @endeach
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>Notice that we used the same section names in both <code>welcome.edge</code> and <code>index.edge</code>. As you would have guessed, we pass <code>articles</code> from the controller. Rest of the statements just take care of rendering the article content (ignore the empty <code>href</code> tag - we&rsquo;ll come back to this).</p>
<p>Let us change the <code>routes.ts</code> file to point to the <code>ArticlesController</code>. We can remove the previously used <code>/articles</code> route for now. The <code>routes.ts</code> file will now have -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Route</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Core/Route&#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">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</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></code></pre></div><p>Edit <code>index</code> function in <code>ArticlesController.ts</code> to return the view rather than plain data.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">(</span><span class="nx">ctx</span>: <span class="kt">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">articles</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Article</span><span class="p">.</span><span class="nx">all</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;articles/index&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">articles</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Here&rsquo;s what changed -</p>
<ol>
<li>We are returning the view instead of data</li>
<li>We pass the data along to the view (and the view can render data in a good way)</li>
</ol>
<p>Refresh the page and see the list of articles.</p>
<p><img loading="lazy" src="/2020/adonis-index-page.jpg" type="" alt="adonis-index-page"  /></p>
<h3 id="tie-articles-to-the-article-list">Tie articles to the article list</h3>
<p>We have to link the list of articles so that we can display content when the user clicks on the link.</p>
<blockquote>
<p>Web is just a bunch of links.</p>
<ul>
<li>Mr. Smarty Pants</li>
</ul>
</blockquote>
<p>Let us create a new detail page that can display article content. Create a new view <code>resources/views/articles/_id.edge</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="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;welcome&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">article</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>{{ article.title }}<span class="p">&lt;/</span><span class="nt">h1</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">section</span><span class="p">&gt;</span>{{ article.content }}<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">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>You know the drill by now - update controller to display this page, which in AdonisJS is the <code>show</code> method.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">show</span><span class="p">(</span><span class="nx">ctx</span>: <span class="kt">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">article</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Article</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="nx">ctx</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;articles/_id&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">article</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>Article.find(ctx.params.id)</code> finds a specific article by querying with <code>id</code>. Then, we return the view by passing the said article details to the view.</p>
<p>Remember that I had asked you to ignore the <code>href</code> tag earlier? Let us change that -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;welcome&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @each(article in articles)
</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;{{ route(&#39;ArticlesController.show&#39;, {id: article.id})}}&#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="p">&gt;</span>{{ article.title }}<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">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  @endeach
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>Navigate to the root and click on any news link to see the new detail page.</p>
<p><img loading="lazy" src="/2020/adonis-detail-page.jpg" type="" alt="adonis-detail-page"  /></p>
<p>We have now tied all loose ends -</p>
<ol>
<li><code>welcome</code> is just a container that shows the actual view <code>articles/index</code></li>
<li><code>articles/index.edge</code> shows a list of articles</li>
<li>When user hits the home page (<code>localhost:3333</code>), <code>route.ts</code> invokes <code>ArticlesController.index</code></li>
<li><code>ArticlesController.index</code> queries for all articles and passes it to <code>articles/index.edge</code> to render</li>
<li>Clicking on a link in <code>articles/index</code> will use a route helper to invoke <code>ArticlesController.show</code> and passes the article id to the view</li>
<li><code>ArticlesController.show</code> will return <code>articles/_id.edge</code> view that will display the article content</li>
</ol>
<p>At a high-level:</p>
<ol>
<li>Router ties the route in the URL (e.g. <code>/</code>, <code>/article/1</code>) to a specific action (or can render the view directly)</li>
<li>Actions are implemented in controllers</li>
<li>Controller queries for data and passes it to a view to render the UI</li>
</ol>
<p>We have created UI and functionality for listing posts and showing a specific post, but we have gone through 75% of all there is to learn :)</p>
<p>Before we go any further, let us style our application a bit.</p>
<h2 id="styling-your-adonisjs-app">Styling your AdonisJS app</h2>
<p>Styling a server-generated app is as simple as including the CSS libraries and sprinkling them classes everywhere. While styles can be as complex as they come, I will choose to use a simple, class-less style library in <a href="https://milligram.io/">Milligram</a>.</p>
<p>Add this one line to the base container.</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></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></code></pre></div><p>Let us create a new css file <code>public/css/styles.css</code> and add that to the mix for customisations. We will not quite discuss styling here - copy and paste CSS from the <a href="https://github.com/prashanth1k/newsie-adonisjs-sample-app/blob/master/public/css/styles.css">Github repo</a>. Add this file to the page.</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></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">href</span><span class="o">=</span><span class="s">&#34;/css/styles.css&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>While we are here, let us rename the container (<code>welcome.edge</code>) to <code>app.edge</code> since that is more near to what the file function is.</p>
<p>Remember to change references to <code>welcome.edge</code> in all views.</p>
<h2 id="enable-authentication">Enable Authentication</h2>
<p>We need our app to support authentication since only registered users can create news articles. Fortunately, Adonis has a powerful authentication module that comes alive with a few code changes.</p>
<p>First, install the additional packages required for auth.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i @adonisjs/auth@alpha phc-argon2 phc-bcrypt
</span></span></code></pre></div><p>Configure auth with 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">node ace invoke @adonisjs/auth
</span></span></code></pre></div><p>Select <code>Web</code> option since we are like to keep things simple. Follow post configuration instructions to change specific sections in <code>kernel.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="nx">Server</span><span class="p">.</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">register</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;Adonis/Core/BodyParserMiddleware&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;App/Middleware/SilentAuth&#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">Server</span><span class="p">.</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">registerNamed</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">auth</span><span class="o">:</span> <span class="s2">&#34;App/Middleware/Auth&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="enable-ui-for-login--registration">Enable UI for Login &amp; Registration</h3>
<p>Change the base layout <code>app.edge</code> to include links to login &amp; logout links.</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">main</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="na">class</span><span class="o">=</span><span class="s">&#34;navbar&#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;logo&#34;</span><span class="p">&gt;&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>Newsie<span class="p">&lt;/</span><span class="nt">a</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">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/about&#34;</span><span class="p">&gt;</span>about<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        @if(auth.user)
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</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;/logout&#34;</span> <span class="na">onclick</span><span class="o">=</span><span class="s">&#34;event.preventDefault();document.getElementById(&#39;logout&#39;).submit()&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            logout
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">form</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;logout&#34;</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/logout&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>{{ csrfField() }}<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">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/articles/new&#34;</span><span class="p">&gt;</span>new<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        @else
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/login&#34;</span><span class="p">&gt;</span>login<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        @endif
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">ul</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">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      @!section(&#34;page&#34;)
</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">main</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">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    (c) Company 42
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">span</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;float:right&#34;</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://github.com/prashanth1k/newsie-adonisjs-sample-app&#34;</span><span class="p">&gt;</span>github<span class="p">&lt;/</span><span class="nt">a</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">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>Remember that edge file supports calculations and inclusion of variables. In addition, we can include simple conditional logic as well. <code> @if(auth.user)</code> checks if a specific object exists and renders the lines until <code>else</code> or <code>endif</code> if the condition is <code>true</code>. We are using the conditional rendering to show <code>login</code> link only if user is not logged in yet.</p>
<p><code>csrfField()</code> is a security function provided by AdonisJS to prevent cross-site forgery. We will use it for all update requests (e.g. POST, PUT, etc.)</p>
<h3 id="user-data-model">User Data Model</h3>
<p>Create user model similar to articles -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"> node ace make model User -cm
</span></span></code></pre></div><p>Change the table migration file <code>database/migrations/&lt;some_num&gt;_users.ts</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">BaseSchema</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Lucid/Schema&#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">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">Users</span> <span class="kr">extends</span> <span class="nx">BaseSchema</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">protected</span> <span class="nx">tableName</span> <span class="o">=</span> <span class="s2">&#34;users&#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">public</span> <span class="kr">async</span> <span class="nx">up() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</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="k">this</span><span class="p">.</span><span class="nx">tableName</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</span><span class="p">)</span> <span class="o">=&gt;</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 class="s2">&#34;id&#34;</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">timestamps</span><span class="p">(</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="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;email&#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="kt">string</span><span class="p">(</span><span class="s2">&#34;password&#34;</span><span class="p">,</span> <span class="mi">180</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="kt">string</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;remember_me&#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></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">down() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</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="k">this</span><span class="p">.</span><span class="nx">tableName</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>Run migrations -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace migration:run
</span></span></code></pre></div><p>Change <code>app/Models/user.ts</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">DateTime</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;luxon&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">BaseModel</span><span class="p">,</span> <span class="nx">column</span><span class="p">,</span> <span class="nx">beforeSave</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Lucid/Orm&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Hash</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Core/Hash&#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">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">User</span> <span class="kr">extends</span> <span class="nx">BaseModel</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">({</span> <span class="nx">isPrimary</span>: <span class="kt">true</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">id</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">({</span> <span class="nx">autoCreate</span>: <span class="kt">true</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">createdAt</span>: <span class="kt">DateTime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">({</span> <span class="nx">autoCreate</span>: <span class="kt">true</span><span class="p">,</span> <span class="nx">autoUpdate</span>: <span class="kt">true</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">updatedAt</span>: <span class="kt">DateTime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">name</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">email</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">password</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">rememberMeToken?</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@beforeSave</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">static</span> <span class="kr">async</span> <span class="nx">hashPassword</span><span class="p">(</span><span class="nx">user</span>: <span class="kt">User</span><span class="p">)</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">user</span><span class="p">.</span><span class="nx">$dirty</span><span class="p">.</span><span class="nx">password</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">user</span><span class="p">.</span><span class="nx">password</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Hash</span><span class="p">.</span><span class="nx">make</span><span class="p">(</span><span class="nx">user</span><span class="p">.</span><span class="nx">password</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><code>hashPassword</code> will hash plain password so that we can securely store it in our database.</p>
<h3 id="user-login-and-registration-controllers">User Login and Registration Controllers</h3>
<p>Change code in <code>app/Controllers/UsersController.ts</code>.</p>
<h4 id="login">Login</h4>
<p>Add code to handle login events.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">login</span><span class="p">({</span> <span class="nx">request</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">auth</span><span class="p">,</span> <span class="nx">session</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</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="k">await</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">attempt</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">input</span><span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">),</span> <span class="nx">request</span><span class="p">.</span><span class="nx">input</span><span class="p">(</span><span class="s1">&#39;password&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/&#39;</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">session</span><span class="p">.</span><span class="nx">flash</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">,</span> <span class="s1">&#39;Login failed. Check email/password &amp; retry.&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;back&#39;</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>Note that -</p>
<ul>
<li><code>await auth.attempt()</code> tries to login using id/password provided by front-end</li>
<li><code>session.flash</code> helps send messages from the business layer back to UI. We will make use of <code>notification</code> in the edge file</li>
<li>successful login will direct user to <code>/</code> = home page. Errors will just go back to the login page</li>
</ul>
<h4 id="register">Register</h4>
<p>It is quite common to validate data sent by the frontend in controllers / models. AdonisJS provides an easy way to validate data but that is not included by default.</p>
<p>Let us install the Adonis Shield package to enable validation in our app -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i @adonisjs/shield@alpha --save
</span></span></code></pre></div><p>Configure shield.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace invoke @adonisjs/shield
</span></span></code></pre></div><p>Follow instructions to register <code>'Adonis/Addons/ShieldMiddleware'</code> in <code>start/kernel.ts</code> file.</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">Server</span><span class="p">.</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">register</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;Adonis/Core/BodyParserMiddleware&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;Adonis/Addons/ShieldMiddleware&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;App/Middleware/SilentAuth&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span></code></pre></div><p>Now you can include functionality provided by shield in your edge files.</p>
<p>Add another method in <code>UsersController.ts</code> to support registration function -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">register</span><span class="p">({</span> <span class="nx">request</span><span class="p">,</span> <span class="nx">auth</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">session</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">valSchema</span> <span class="o">=</span> <span class="nx">schema</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">email</span>: <span class="kt">schema.string</span><span class="p">({</span> <span class="nx">trim</span>: <span class="kt">true</span> <span class="p">},</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="nx">rules</span><span class="p">.</span><span class="kt">unique</span><span class="p">({</span> <span class="nx">table</span><span class="o">:</span> <span class="s1">&#39;users&#39;</span><span class="p">,</span> <span class="nx">column</span><span class="o">:</span> <span class="s1">&#39;email&#39;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">rules</span><span class="p">.</span><span class="nx">maxLength</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">rules</span><span class="p">.</span><span class="nx">email</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">password</span>: <span class="kt">schema.string</span><span class="p">({</span> <span class="nx">trim</span>: <span class="kt">true</span> <span class="p">},</span> <span class="p">[</span><span class="nx">rules</span><span class="p">.</span><span class="nx">maxLength</span><span class="p">(</span><span class="mi">180</span><span class="p">),</span> <span class="nx">rules</span><span class="p">.</span><span class="nx">required</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">data</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">request</span><span class="p">.</span><span class="nx">validate</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">schema</span>: <span class="kt">valSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">messages</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;email.unique&#39;</span><span class="o">:</span> <span class="s1">&#39;Email already exists&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;email.maxLength&#39;</span><span class="o">:</span> <span class="s1">&#39;Email can be upto 255 characters&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;email.email&#39;</span><span class="o">:</span> <span class="s1">&#39;Invalid email&#39;</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="kr">const</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">User</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">email</span>: <span class="kt">data.email</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">password</span>: <span class="kt">data.password</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="k">await</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">login</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">session</span><span class="p">.</span><span class="nx">flash</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">,</span> <span class="s1">&#39;Registered.&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div><p>This is very similar to the login method, but has a few more goodies.</p>
<p><code>const valSchema = schema.create()</code> enables us to easily create custom validation rules and messages using Adonis Shield. We check whether the email already exists, email is a valid email string and whether it has max 255 characters. If all validations pass, we login the user and redirect them to the home page.</p>
<p>Both the methods described so far provide the control layer. We need to render the views as well.</p>
<h4 id="show-login-and-register-pages">Show Login and Register Pages</h4>
<p>Add two more methods to show login and registration screens.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">showLogin</span><span class="p">({</span> <span class="nx">view</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</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">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;auth/login&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">user</span><span class="o">:</span> <span class="p">{</span> <span class="nx">email</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">password</span><span class="o">:</span> <span class="s1">&#39;&#39;</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></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">showRegister</span><span class="p">({</span> <span class="nx">view</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</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">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;auth/register&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">user</span><span class="o">:</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">email</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">password</span><span class="o">:</span> <span class="s1">&#39;&#39;</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>We pass dummy objects like <code>user: { email: '', password: '' }</code> to demonstrate that we could pass predefault strings to the UI if desired.</p>
<p>Before we forget - code the logout event as well..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">logout</span><span class="p">({</span> <span class="nx">auth</span><span class="p">,</span> <span class="nx">response</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">await</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">logout</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="user-login-and-registration-ui">User Login and Registration UI</h3>
<p>Create edge views to enable user to login / register.</p>
<h4 id="sign-up-screen">Sign up screen</h4>
<p>Create a new file <code>resources/views/auth/register.edge</code>. Input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kd">@layout</span><span class="p">(</span><span class="s2">&#34;app&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@section</span><span class="p">(</span><span class="s2">&#34;page&#34;</span><span class="p">)</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;padding-left: 20%;padding-right: 20%&#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;article-title&#34;</span><span class="p">&gt;</span><span class="nx">Sign</span> <span class="nx">up</span><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="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;errors.email&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;errors.email&#34;</span><span class="p">)}}</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 class="kd">@endif</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;notification&#34;</span><span class="p">)}}</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 class="kd">@endif</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;{{ `/register`}}&#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="p">{{</span> <span class="nx">csrfField</span><span class="p">()</span> <span class="p">}}</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;name&#34;</span><span class="p">&gt;</span><span class="nx">Name</span><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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.name}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;name&#34;</span> <span class="na">required</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><span class="nx">Email</span><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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.email}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;email&#34;</span> <span class="na">required</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;password&#34;</span><span class="p">&gt;</span><span class="nx">Password</span><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">type</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.password}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">required</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">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span><span class="nx">Sign</span> <span class="nx">up</span><span class="p">&lt;/</span><span class="nt">button</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="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="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">@endsection</span>
</span></span></code></pre></div><p>Note that -</p>
<ol>
<li>We continue using <code>app.edge</code> as the base layout</li>
<li>We used <code>flashMessages</code> to provide a way to show error messages and notifications on the UI</li>
</ol>
<h4 id="login-screen">Login screen</h4>
<p>Create a new file <code>resources/views/auth/register.edge</code>. Input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kd">@layout</span><span class="p">(</span><span class="s2">&#34;app&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@section</span><span class="p">(</span><span class="s2">&#34;page&#34;</span><span class="p">)</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;padding-left: 20%;padding-right: 20%&#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;article-title&#34;</span><span class="p">&gt;</span><span class="nx">Login</span><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">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;errors.title&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;errors.title&#34;</span><span class="p">)}}</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 class="kd">@endif</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;notification&#34;</span><span class="p">)}}</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 class="kd">@endif</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;{{ `/login`}}&#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="p">{{</span> <span class="nx">csrfField</span><span class="p">()</span> <span class="p">}}</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><span class="nx">Email</span><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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.email}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;email&#34;</span> <span class="na">required</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;password&#34;</span><span class="p">&gt;</span><span class="nx">Password</span><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">type</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.password}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">required</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">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span><span class="nx">Login</span><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">class</span><span class="o">=</span><span class="s">&#34;article-meta&#34;</span><span class="p">&gt;</span> <span class="nx">Not</span> <span class="nx">registered</span><span class="o">?</span> <span class="p">&lt;</span><span class="nt">a</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/register&#34;</span><span class="p">&gt;</span><span class="nx">Sign</span> <span class="nx">up</span><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&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">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">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">@endsection</span>
</span></span></code></pre></div><h3 id="user-routes">User Routes</h3>
<p>Add below routes to <code>start/routes.ts</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">Route</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/login&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.login&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/login&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.showLogin&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/register&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.register&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/register&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.showRegister&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/logout&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.logout&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>And.. you are done just like that. Try out logging in / signin up to use the application.</p>
<h2 id="do-more-with-articles">Do More With Articles</h2>
<p>While our articles functionality is all powerful, our app still lacks a few things-</p>
<ol>
<li>We can provide a way to see &ldquo;proper&rdquo; URLs for individual articles. A &ldquo;slug&rdquo; is a URL-friendly article id that is easier to read</li>
<li>Articles do not have any formatting now. We will support markdown content editing for easier content authoring / assimilation</li>
<li>Make the user experience and navigation better</li>
</ol>
<p>Let&rsquo;s get to it.</p>
<h3 id="list-articles">List Articles</h3>
<p>The home page shows a bunch of links right now. Change that to display news cards with a title and content preview.</p>
<p>Modify <code>resources/views/articles/index.edge</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="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;) 
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">section</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;hero&#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;row&#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;column&#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;title&#34;</span><span class="p">&gt;</span>Welcome to newsie!<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">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle&#34;</span><span class="p">&gt;</span>Positive news across the world.<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">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;column center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">        <span class="na">src</span><span class="o">=</span><span class="s">&#34;/images/smiley.png&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">style</span><span class="o">=</span><span class="s">&#34;width:150px;height:150px;margin:auto;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">class</span><span class="o">=</span><span class="s">&#34;column&#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">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">section</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;row row-wrap&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @each(article in articles)
</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;column column-50&#34;</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="na">class</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      @if(auth.user)
</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;/articles/{{article.id}}/edit&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-meta-small&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>edit<span class="p">&lt;/</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      @endif
</span></span><span class="line"><span class="cl">      <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">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ route(&#39;ArticlesController.show&#39;, {id: article.slug}) }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{ article.title }}
</span></span><span class="line"><span class="cl">        <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">h3</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">class</span><span class="o">=</span><span class="s">&#34;article-meta&#34;</span><span class="p">&gt;</span>Updated: {{article.publishDate}}<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">p</span><span class="p">&gt;</span>{{{ article.content ? article.content.substring(0,100) : &#34;&#34; }}}<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">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @endeach
</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">@endsection
</span></span></code></pre></div><p>A couple of interesting things to note -</p>
<ol>
<li>There is an <code>edit</code> link at the top of each article. This shows up only for logged in users</li>
<li>We use a &ldquo;route helper&rdquo; in <code>&lt;a href=&quot;{{ route('ArticlesController.show', {id: article.slug}) }}&quot;&gt;</code> to directly refer to the AdonisJS route rather than use the URL to reach the article detail view</li>
</ol>
<h3 id="show-article-detail">Show Article Detail</h3>
<p>There are two changes to be done at this time -</p>
<ul>
<li>Treat content in <code>content</code> as markdown. To render markdown in HTML, we use a package called &ldquo;marked&rdquo;.</li>
<li>Let us start using a &ldquo;slug&rdquo; instead of a cryptic &ldquo;id&rdquo; field in URL. We will use a package called &ldquo;slugify&rdquo; to convert title to a slug</li>
</ul>
<p>Install packages -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i marked slugify
</span></span></code></pre></div><p>Modify the model <code>app/Models/Article.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// other lines
</span></span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">Article</span> <span class="kr">extends</span> <span class="nx">BaseModel</span> <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></span><span class="line"><span class="cl">  <span class="kd">@computed</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">get</span> <span class="nx">fmtContent() {</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="kr">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="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">content</span> <span class="o">?</span> <span class="nx">marked</span><span class="p">(</span><span class="k">this</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="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></span><span class="line"><span class="cl">  <span class="kd">@beforeSave</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">static</span> <span class="kr">async</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">article</span>: <span class="kt">Article</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slugify</span> <span class="o">=</span> <span class="kr">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></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">article</span><span class="p">.</span><span class="nx">$original</span><span class="p">.</span><span class="nx">slug</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">article</span><span class="p">.</span><span class="nx">$attributes</span><span class="p">.</span><span class="nx">slug</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">article</span><span class="p">.</span><span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">article</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="kt">true</span><span class="p">,</span> <span class="nx">strict</span>: <span class="kt">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">article</span><span class="p">.</span><span class="nx">$dirty</span><span class="p">.</span><span class="nx">slug</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">article</span><span class="p">.</span><span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">article</span><span class="p">.</span><span class="nx">slug</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span>: <span class="kt">true</span><span class="p">,</span> <span class="nx">strict</span>: <span class="kt">true</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 changes are fairly straight-forward. We created a computed field to convert markdown to HTML (which can inturn be used in our views), and auto-filled the slug before saving the record.</p>
<p>Change <code>resources/views/articles/_id.edge</code> that shows the detail article 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="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</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">  @if(auth.user)
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-meta-small&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/articles/{{article.id}}/edit&#34;</span><span class="p">&gt;</span>edit<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @endif
</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;article-title&#34;</span><span class="p">&gt;</span>{{ article.title }}<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">article</span><span class="p">&gt;</span>{{{ article.fmtContent }}}<span class="p">&lt;/</span><span class="nt">article</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">@endsection
</span></span></code></pre></div><p>Note that we have now used <code>fmtContent</code> and <code>{{{ }}}</code> notation to directly create HTML based on the field content.</p>
<h3 id="create-article">Create Article</h3>
<p>Create a new view <code>resources/views/articles/new.edge</code> and input 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="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</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">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-title&#34;</span><span class="p">&gt;</span>New Article<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">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @if(flashMessages.has(&#39;errors.title&#39;))
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>{{flashMessages.get(&#34;errors.title&#34;)}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @endif @if(flashMessages.has(&#39;notification&#39;))
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>{{flashMessages.get(&#34;notification&#34;)}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @endif
</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;/articles/&#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">      {{ csrfField() }}
</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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.title || &#39;&#39;}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#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;slug&#34;</span><span class="p">&gt;</span>Slug<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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.slug || &#39;&#39;}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;slug&#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">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>Post 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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">rows</span><span class="o">=</span><span class="s">&#34;10&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{ article.content || &#39;&#39; }}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">textarea</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">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">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">article</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">@endsection
</span></span></code></pre></div><p>Nothing we haven&rsquo;t seen before.</p>
<h3 id="update-article">Update Article</h3>
<p>Create a new view <code>resources/views/articles/edit.edge</code> to edit a given article. In our case, the code here will be almost same as <code>new</code>. Input 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="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</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">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-title&#34;</span><span class="p">&gt;</span>Update Article<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">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @if(flashMessages.has(&#39;errors.title&#39;))
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{flashMessages.get(&#34;errors.title&#34;)}}
</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">    @endif
</span></span><span class="line"><span class="cl">    @if(flashMessages.has(&#39;notification&#39;))
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            {{flashMessages.get(&#34;notification&#34;)}}
</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">    @endif
</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;{{ `/articles/${article.id}?_method=PATCH`}}&#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">        {{ csrfField() }}
</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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.title}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#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;slug&#34;</span><span class="p">&gt;</span>Slug<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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.slug}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;slug&#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">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>Post 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">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">rows</span><span class="o">=</span><span class="s">&#34;10&#34;</span><span class="p">&gt;</span>{{article.content}}<span class="p">&lt;/</span><span class="nt">textarea</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">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></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">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p><code>_method=PATCH</code> in form action is what is called as &ldquo;method spoofing&rdquo;. This allows us to send a <code>patch</code> method in the HTTP POST request. You need to enable method spoofing in AdonisJS by making the below configuration change in <code>app.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">allowMethodSpoofing</span>: <span class="kt">true</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="article-routes">Article Routes</h3>
<p>Finally, change the article routes.</p>
<p>Let us -</p>
<ol>
<li>Support edit, update and new routes to views created so far</li>
<li>Require user to be logged in to create or update articles</li>
</ol>
<p>Modify <code>app/start/routes.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/about&#34;</span><span class="p">).</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;about&#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">Route</span><span class="p">.</span><span class="nx">group</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/new&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.create&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/:id/edit&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.edit&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</span><span class="p">.</span><span class="nx">patch</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.update&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</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="s2">&#34;ArticlesController.store&#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 class="nx">prefix</span><span class="p">(</span><span class="s2">&#34;articles&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">middleware</span><span class="p">(</span><span class="s2">&#34;auth&#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">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/articles/:id&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.show&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>The auth middleware included in the route group takes care of checking for valid user and redirecting user to login screen if not already logged in. Anonymous users can just view the article list and browse articles.</p>
<p>We are done with all changes required to provide a cool-looking app to create, edit and view news articles.</p>
<h2 id="finis">Finis</h2>
<p>While getting to the finish line took a few hundred lines, you will get used to the steps required to enable functionality in AdonisJS in no time. If you have experience with other bare-bones frameworks, you will come to appreciate the ease of customisation and the structured/standardised coding approach that makes life easier for everyone.</p>
<p>Go ahead - make your news app available to the world, spread positivity and create more awesome apps.</p>
<p>The repository with full code is at <a href="https://github.com/prashanth1k/newsie-adonisjs-sample-app">https://github.com/prashanth1k/newsie-adonisjs-sample-app</a>.</p>
]]></content:encoded>
    </item>
    
    <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>
    
  </channel>
</rss>
