<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[XpresserJs Framework]]></title><description><![CDATA[Official Blog for Xpresserjs Nodejs Framework]]></description><link>https://blog.xpresserjs.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1607065854199/D64S35imV.png</url><title>XpresserJs Framework</title><link>https://blog.xpresserjs.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 02:30:00 GMT</lastBuildDate><atom:link href="https://blog.xpresserjs.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Build a URL Shortener with XpresserJs]]></title><description><![CDATA[What is a url shortener?
A URL shortener is a simple tool that takes a long URL and turns it into whatever URL you would like it to be.
Lets get started!
Create a new xpresserjs project using the xjs-cli Command line tool
npx xjs-cli new url-shortner...]]></description><link>https://blog.xpresserjs.com/build-a-url-shortener-with-xpresserjs</link><guid isPermaLink="true">https://blog.xpresserjs.com/build-a-url-shortener-with-xpresserjs</guid><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Xpresser]]></dc:creator><pubDate>Sun, 01 Aug 2021 19:32:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627729897082/iqwMusmx6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="what-is-a-url-shortener">What is a url shortener?</h2>
<p>A URL shortener is a simple tool that takes a long URL and turns it into whatever URL you would like it to be.</p>
<h2 id="lets-get-started">Lets get started!</h2>
<p>Create a new xpresserjs project using the <code>xjs-cli</code> Command line tool</p>
<pre><code class="lang-sh">npx xjs-cli new url-shortner
</code></pre>
<p>When asked for Language and Boilerplate select <strong>Javascript &amp; Simple App</strong> Boilerplate</p>
<pre><code class="lang-shell">Project Language: Javascript
Project Boilerplate: Simple App (Hello World, No views)
</code></pre>
<p><code>cd</code> into the new project folder and run <code>yarn</code> or <code>npm install</code> to install dependencies.</p>
<h2 id="database">Database</h2>
<p>This tutorial will make use of <strong>MongoDB</strong> using <strong>xpress-mongo</strong> a lightweight ODM for Nodejs MongoDB.
<br />Note: We assume you are already familiar with the MongoDB Ecosystem and have mongodb already installed in your
machine.</p>
<h3 id="setup-database-connection">Setup Database Connection</h3>
<p>For quick database setup we will use xpresser's <strong>official</strong> <code>xpress-mongo</code>
plugin: <code>@xpresser/xpress-mongo</code></p>
<p>Following the installation instructions on the npm page, we need to install <code>xpress-mongo</code>
and <code>@xpresser/xpress-mongo</code></p>
<ul>
<li><strong><a target="_blank" href="https://www.npmjs.com/package/xpress-mongo">xpress-mongo</a></strong> - A Nodejs lightweight ODM for MongoDB.</li>
<li><strong><a target="_blank" href="https://www.npmjs.com/package/@xpresser/xpress-mongo">@xpresser/xpress-mongo</a></strong> - Xpresser's Plugin that connects
to MongoDB using xpress-mongo and provides the Connection pool throughout your application's lifecycle.</li>
</ul>
<pre><code class="lang-shell">npm i xpress-mongo @xpresser/xpress-mongo
# OR
yarn add xpress-mongo @xpresser/xpress-mongo
</code></pre>
<p>Create a <strong>plugins.json</strong> file in your <strong>backend</strong> folder. i.e. <code>backend/plugins.json</code> and paste the json below.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"npm://@xpresser/xpress-mongo"</span>: <span class="hljs-literal">true</span>
}
</code></pre>
<p>This file tells <code>xpresser</code> that we want to use <code>@xpresser/xpress-mongo</code> plugin.</p>
<h2 id="configure">Configure</h2>
<p>Let's modify our configuration. Goto File: <strong>config.js</strong></p>
<h4 id="change-name">Change Name</h4>
<ul>
<li>Change project <strong>name</strong> from <code>Xpresser-Simple-App</code> to <code>Url Shortener</code> or any custom name you prefer.</li>
<li>Add the database config below to your config file.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-comment">// .... After every other config.</span>
  <span class="hljs-attr">mongodb</span>: {
    <span class="hljs-attr">url</span>: <span class="hljs-string">'mongodb://127.0.0.1:27017'</span>,
    <span class="hljs-attr">database</span>: <span class="hljs-string">'url-shortener'</span>,
    <span class="hljs-attr">options</span>: {
      <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>
    }
  }
}
</code></pre>
<h2 id="frontend">Frontend</h2>
<p>Let's make an index view. (xpresser supports Ejs by default)</p>
<p>Note: Since we now have xjs-cli in our project, we can use the command <code>xjs</code> without npx in our project root</p>
<pre><code class="lang-shell">xjs make:view index
</code></pre>
<p>this will create a .ejs file @ <code>backend/views/index.ejs</code>. Paste the code below in it.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Xpresser URL Shortener<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">confirmDeleteUrl</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> canDelete = confirm(<span class="hljs-string">'Are you sure you want to delete this URL?'</span>);
      <span class="hljs-keyword">if</span> (!canDelete) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-2xl mx-auto mt-5"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-2xl font-medium text-center text-gray-500"</span>&gt;</span>Shorten Your URL<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Input Form --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/shorten"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"my-5 flex mx-2 sm:mx-0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your long URL"</span> <span class="hljs-attr">required</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full border-l-2 border-t-2 border-b-2 py-2 px-3 md:text-lg text-blue-800
                   rounded-l-lg shadow-sm focus:outline-none"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-initial"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"md:py-3 py-2.5 px-4 bg-blue-800 text-white rounded-r-lg shadow-sm focus:outline-none"</span>&gt;</span>
        Shorten!
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Url Table--&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"overflow-x-auto"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-10 w-full"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">thead</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"border-b-2 mb-3"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-800 text-left"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"px-2"</span>&gt;</span>URL<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"px-2"</span>&gt;</span>Short ID<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"px-2"</span>&gt;</span>Clicks<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"px-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- Url Table Body--&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-3"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-800"</span>&gt;</span>
            /AyXvu
          <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">small</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-500"</span>&gt;</span>
            https://xpresserjs.com/xpress-mongo/events
          <span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2"</span>&gt;</span>AyXvu<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2 text-green-600 pl-5"</span>&gt;</span>22<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/delete"</span> <span class="hljs-attr">onsubmit</span>=<span class="hljs-string">"return confirmDeleteUrl(this)"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"shortId"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"realShortId"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-red-600"</span>&gt;</span>delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The above is a simple HTML page that shows a form to shorten urls with a table displaying shortened urls.</p>
<h2 id="control-requests">Control Requests</h2>
<p>Empty file: <code>backend/controllers/AppController.js</code> and paste the code below.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {

  <span class="hljs-attr">name</span>: <span class="hljs-string">'AppController'</span>,

  <span class="hljs-comment">/**
   * Index Page Action.
   * For route "/"
   */</span>
  index(http) {
    <span class="hljs-keyword">return</span> http.view(<span class="hljs-string">'index'</span>);
  },
};
</code></pre>
<h3 id="preview">Preview</h3>
<p>Run <code>nodemon app.js</code> in the project root folder and click the server URL to preview the HTML in <code>index.ejs</code>
i.e. <a target="_blank" href="http://localhost:3000">http://localhost:3000</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627731764890/OaCCzfe-_.png" alt="index_preview.png" /></p>
<h2 id="making-it-work">Making it work</h2>
<p>Let's make this work with real values from the database.</p>
<h3 id="create-url-model">Create Url Model</h3>
<p>To create a model, run the command:</p>
<pre><code class="lang-shell">xjs make:model Url
</code></pre>
<p>Creates a model @ <code>backend/models/Url.js</code>.</p>
<h3 id="adding-database-schema">Adding Database Schema</h3>
<p>In your new model you will see default fields: <code>updatedAt</code> &amp; <code>createdAt</code>. we need to add other fields like <code>url</code>
, <code>shortId</code> &amp; <code>clicks</code>.</p>
<p>Note: The <code>updatedAt</code> field is not needed.</p>
<pre><code class="lang-js">schema = {
  <span class="hljs-attr">url</span>: is.String().required(),
  <span class="hljs-attr">shortId</span>: is.String().required(),
  <span class="hljs-attr">clicks</span>: is.Number().required(),
  <span class="hljs-attr">createdAt</span>: is.Date().required()
};
</code></pre>
<p>Your model file should look exactly like</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> {is, XMongoModel} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"xpress-mongo"</span>);
<span class="hljs-keyword">const</span> {UseCollection} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@xpresser/xpress-mongo"</span>);

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Url</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">XMongoModel</span> </span>{
  <span class="hljs-comment">// Set Model Schema</span>
  <span class="hljs-keyword">static</span> schema = {
    <span class="hljs-attr">url</span>: is.String().required(),
    <span class="hljs-attr">shortId</span>: is.String().required(),
    <span class="hljs-attr">clicks</span>: is.Number().required(),
    <span class="hljs-attr">createdAt</span>: is.Date().required()
  };
}

<span class="hljs-comment">// Map Model to Collection `urls`</span>
<span class="hljs-comment">// .native() will be made available for use.</span>
UseCollection(Url, <span class="hljs-string">"urls"</span>);

<span class="hljs-built_in">module</span>.exports = Url;
</code></pre>
<h2 id="add-url">Add Url</h2>
<p>In our <strong>index.ejs</strong> file, the url <code>form</code> is sent via POST method to action: <code>/shorten</code></p>
<p>Let's register path <code>/shorten</code> in the <strong>routes.js</strong> file.</p>
<p>Add this line to the end your routes file.</p>
<pre><code class="lang-javascript">router.post(<span class="hljs-string">'/shorten'</span>, <span class="hljs-string">'App@shorten'</span>);
</code></pre>
<p>This simply means that we want the <code>shorten</code> method in <code>AppController</code> to handle the POST request to <code>/shorten</code></p>
<h2 id="add-shorten-method">Add shorten method</h2>
<p>Before we add the shorten method, lets import the <code>Url</code> model at the top of <code>AppController</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Url = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../models/Url"</span>);
</code></pre>
<p>Then Paste the  <code>shorten</code> method below in your <code>AppController</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-keyword">async</span> shorten(http) {
    <span class="hljs-comment">// Get url from request body.</span>
    <span class="hljs-keyword">const</span> url = http.body(<span class="hljs-string">"url"</span>);
    <span class="hljs-comment">// Generate short url using xpresser's randomStr helper.</span>
    <span class="hljs-keyword">const</span> shortId = http.$(<span class="hljs-string">"helpers"</span>).randomStr(<span class="hljs-number">6</span>)

    <span class="hljs-keyword">try</span> {
      <span class="hljs-built_in">console</span>.log(
          <span class="hljs-keyword">await</span> Url.new({url, shortId})
      )
    } <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-built_in">console</span>.log(e)
    }

    <span class="hljs-keyword">return</span> http.redirectBack()
  }
}
</code></pre>
<ul>
<li>First, Get the <code>url</code> sent by the frontend form.</li>
<li>Generate a shortId using xpresser's <code>randomStr</code> helper.</li>
<li>Try adding a new document to the database. Logs error or new URL document.</li>
<li>Redirect back to sender i.e. frontend.</li>
</ul>
<h4 id="lets-test-the-progress-so-far">Let's test the progress so far.</h4>
<p>Note: Because we made use of <code>nodemon</code> when running <code>app.js</code> earlier on, we don't need to refresh our server
since  <code>nodemon</code> does that for you.</p>
<p>Refresh your browser, Then shorten a long url.</p>
<p>A look alike of the log below should show in your xpresser console logs before the request redirects back.</p>
<pre><code><span class="hljs-selector-tag">Url</span> {
  <span class="hljs-attribute">data</span>: {
    <span class="hljs-attribute">_id</span>: <span class="hljs-number">60</span>c357723f80e72678b72ba7,
    <span class="hljs-attribute">url</span>: <span class="hljs-string">'https://xpresserjs.com/xpress-mongo/events'</span>,
    <span class="hljs-attribute">shortId</span>: <span class="hljs-string">'AyXvu'</span>,
    <span class="hljs-attribute">clicks</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attribute">createdAt</span>: <span class="hljs-number">2021</span><span class="hljs-attribute">-06-11T12</span>:<span class="hljs-number">30</span>:<span class="hljs-number">42.064</span>Z
  }
}
</code></pre><p>The data above is saved to your database but our <code>index.ejs</code> does not show it yet. Now let's make our <code>index.ejs</code> use
dynamic values from the database.</p>
<p>Remember our <code>index.ejs</code> is rendered by the <code>AppController@index</code> controller route action. So that is where we will get
a list of URLs from the database and provide it to <code>index.ejs</code></p>
<p>Modify the <code>index</code> method in <code>AppController</code> to look like so:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {

  <span class="hljs-keyword">async</span> index(http) {
    <span class="hljs-comment">// Get all urls from db.</span>
    <span class="hljs-keyword">const</span> urls = <span class="hljs-keyword">await</span> Url.find();

    <span class="hljs-comment">// Share urls with index.ejs</span>
    <span class="hljs-keyword">return</span> http.view(<span class="hljs-string">"index"</span>, {urls});
  },

}
</code></pre>
<p>Next lets modify <code>index.ejs</code> file to use the <code>urls</code> data provided. Change this section of your <code>index.ejs</code> file</p>
<p>Change the table body i.e. <code>&lt;tbody&gt;</code></p>
<h5 id="from">FROM</h5>
<pre><code><span class="hljs-comment">&lt;!-- Url Table Body--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-3"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-800"</span>&gt;</span>
      /AyXvu
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">small</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-500"</span>&gt;</span>
      https://xpresserjs.com/xpress-mongo/events
    <span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2"</span>&gt;</span>AyXvu<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2 text-green-600 pl-5"</span>&gt;</span>22<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/delete"</span> <span class="hljs-attr">onsubmit</span>=<span class="hljs-string">"return confirmDeleteUrl(this)"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"shortId"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"realShortId"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-red-600"</span>&gt;</span>delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
</code></pre><h5 id="to">TO</h5>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Url Table Body--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-3"</span>&gt;</span>
<span class="hljs-comment">&lt;!--Loop Through Urls--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">for</span>(<span class="hljs-attr">const</span> <span class="hljs-attr">url</span> <span class="hljs-attr">of</span> <span class="hljs-attr">urls</span>) { <span class="hljs-attr">const</span> <span class="hljs-attr">shortUrl</span> = <span class="hljs-string">"/"</span> + <span class="hljs-attr">url.shortId</span>; %&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"&lt;%= shortUrl %&gt;"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-800"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">shortUrl</span> %&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">small</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-500"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">url.url</span> %&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">url.shortId</span> %&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-2 pl-5 text-green-600"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">url.clicks</span> %&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/delete"</span> <span class="hljs-attr">onsubmit</span>=<span class="hljs-string">"return confirmDeleteUrl(this)"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"shortId"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"&lt;%= url.shortId %&gt;"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-red-600"</span>&gt;</span>delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%</span> } %&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
</code></pre>
<p>Here we are looping through <code>urls</code> and displaying them on the table.</p>
<p>Reload the index page, and you should see the long URL(s) that were previously saved to the database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627732512352/fQ22i_e9p.png" alt="loop_url_preview.png" />
Clicking a shortUrl link will display xpresser's default <code>404 Error Page</code> and this is because we haven't declared the
route that will redirect our short URL to its long URL.</p>
<h2 id="handling-short-url-requests">Handling short URL requests.</h2>
<p>Let's create a route that will handle a short URL. Add the route below at the end of your routes file.</p>
<pre><code class="lang-js">router.get(<span class="hljs-string">"/:shortId"</span>, <span class="hljs-string">"App@redirect"</span>);
</code></pre>
<p>This means that we want the <code>redirect</code> method in <code>AppController</code> to handle GET request sent to <code>/:shortId</code>
<br />Note: <code>:shortId</code> in the URL indicates a dynamic route parameter.</p>
<pre><code><span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:3000/abcdef</span>
<span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:3000/uvwxyz</span>
</code></pre><p>Given the example above <code>:shortId</code> represents <code>abcdef</code> and <code>uvwxyz</code>.</p>
<h3 id="create-the-redirect-method">Create the redirect method.</h3>
<p>Paste the  <code>redirect</code> method below in your <code>AppController</code>.</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-keyword">async</span> redirect(http) {
    <span class="hljs-comment">// Get shortId from request params.</span>
    <span class="hljs-keyword">const</span> {shortId} = http.params;

    <span class="hljs-comment">// find url using shortId</span>
    <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">await</span> Url.findOne({shortId});

    <span class="hljs-comment">// if no url found then send a 404 error message.</span>
    <span class="hljs-keyword">if</span> (!url) <span class="hljs-keyword">return</span> http.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">`&lt;h3&gt;Short url not found!&lt;/h3&gt;`</span>);

    <span class="hljs-comment">// Increment clicks count.</span>
    <span class="hljs-keyword">await</span> url.updateRaw({
      <span class="hljs-attr">$inc</span>: {<span class="hljs-attr">clicks</span>: <span class="hljs-number">1</span>}
    });

    <span class="hljs-comment">// redirect to long url</span>
    <span class="hljs-keyword">return</span> http.redirect(url.data.url);
  }
}
</code></pre>
<ul>
<li>First, we grab the <code>shortId</code> from the route url params.</li>
<li>Find the url using xpress-mongo's <code>findOne</code> which returns a model instance when found or <code>null</code> if not found.</li>
<li>If the result from DB is <code>null</code> we return a 404 response.</li>
<li>Next, increment the clicks count.</li>
<li>Redirect to long URL.</li>
</ul>
<p>Now Refresh your browser and click any of the short links. You will be redirected to the long URL and the clicks count
should update also.</p>
<h2 id="delete-url">Delete Url</h2>
<p>The delete button when clicked and confirmed will show a <code>/delete</code> <strong>404 Error Page</strong> and this is because we haven't
declared a route &amp; controller action for it yet.</p>
<p>Let's add a POST <code>/delete</code> route before our <code>redirect</code> route. Your route file should be looking like this.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> {getInstanceRouter} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"xpresser"</span>);
<span class="hljs-comment">/**
 * See https://xpresserjs.com/router/
 */</span>
<span class="hljs-keyword">const</span> router = getInstanceRouter();

<span class="hljs-comment">/**
 * Url: "/" points to AppController@index
 * The index method of the controller.
 */</span>
router.get(<span class="hljs-string">"/"</span>, <span class="hljs-string">"App@index"</span>).name(<span class="hljs-string">"index"</span>);
router.post(<span class="hljs-string">"/shorten"</span>, <span class="hljs-string">"App@shorten"</span>);
router.post(<span class="hljs-string">"/delete"</span>, <span class="hljs-string">"App@delete"</span>);
router.get(<span class="hljs-string">"/:shortId"</span>, <span class="hljs-string">"App@redirect"</span>);
</code></pre>
<h4 id="why-delete-before-redirect-route">Why <code>delete</code> before <code>redirect</code> route?</h4>
<p>If the <code>/delete</code> route is placed after the <code>/:shortId</code> route, the router will assume the keyword <code>delete</code> is
a  <code>shortId</code> route parameter because <code>/:shortId</code> was declared first.</p>
<h3 id="create-the-delete-method">Create the delete method</h3>
<p>Paste the <code>delete</code> method below in your <code>AppController</code>.</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-keyword">async</span> <span class="hljs-keyword">delete</span>(http) {
    <span class="hljs-comment">// Get shortId from request body.</span>
    <span class="hljs-keyword">const</span> shortId = http.body(<span class="hljs-string">"shortId"</span>);

    <span class="hljs-comment">// Delete from database</span>
    <span class="hljs-keyword">await</span> Url.native().deleteOne({shortId});

    <span class="hljs-keyword">return</span> http.redirectBack();
  }
}
</code></pre>
<p>Refresh your browser and try the delete feature.</p>
<h5 id="hurray-you-now-have-your-own-url-shortener-application">Hurray!! you now have your own URL shortener Application</h5>
<p>Git Repo: <a target="_blank" href="https://github.com/xpresserjs/url-shortner-tutorial">https://github.com/xpresserjs/url-shortner-tutorial</a></p>
]]></content:encoded></item><item><title><![CDATA[XpresserJs, First post on Hashnode.]]></title><description><![CDATA[Hey There, 👋
So we have decided to host the blog version of the  xpresserjs  framework on  hashnode.com. We were a few days away from creating our own markdown supported blog from scratch before we learned about hashnode and so far it feels like hom...]]></description><link>https://blog.xpresserjs.com/xpresserjs-first-post-on-hashnode</link><guid isPermaLink="true">https://blog.xpresserjs.com/xpresserjs-first-post-on-hashnode</guid><category><![CDATA[Node.js]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[javascript framework]]></category><category><![CDATA[Express.js]]></category><category><![CDATA[mvc]]></category><dc:creator><![CDATA[Xpresser]]></dc:creator><pubDate>Fri, 04 Dec 2020 07:03:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607065401034/Cc0IFKVIx.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey There, 👋</p>
<p>So we have decided to host the blog version of the  <a target="_blank" href="https://xpresserjs.com">xpresserjs</a>  framework on  <a target="_blank" href="https://hashnode.com">hashnode.com</a>. We were a few days away from creating our own markdown supported blog from scratch before we learned about hashnode and so far it feels like home. 😉</p>
<h3 id="what-is-xpresserjs">What is XpresserJs</h3>
<p>XpresserJs is a server-side and command-line framework for Nodejs built using <a target="_blank" href="https://expressjs.com">express</a> as it's server.</p>
<h5 id="visit-the-official-documentationhttpsxpresserjscom-to-learn-more-about-xpresserjs">Visit the <a target="_blank" href="https://xpresserjs.com">official documentation</a> to learn more about XpresserJs</h5>
<h4 id="a-few-lines-about-xpresserjs">A few lines about xpresserjs</h4>
<p>Create file <strong>server.js</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import Xpresser</span>
<span class="hljs-keyword">const</span> xpresser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"xpresser"</span>)

<span class="hljs-comment">// Initialize with your configuration.</span>
<span class="hljs-keyword">const</span> $ = xpresser.init({
     <span class="hljs-attr">env</span>: process.env.NODE_ENV,
     <span class="hljs-attr">name</span>: <span class="hljs-string">"My First Xpresser Project"</span>
     <span class="hljs-attr">paths</span>: {
          <span class="hljs-attr">base</span>: __dirname,
          <span class="hljs-attr">routesFile</span>: <span class="hljs-string">"routes.js"</span>,
     }
})

<span class="hljs-comment">// Boot Xpresser</span>
$.boot();
</code></pre>
<p>With these few lines of code, you have a full MVC framework waiting for you to start building.</p>
<p>Run <code>node server.js</code> and you should see a beautiful 404 error page. This is because no routes have been added.</p>
<h3 id="adding-routes">Adding routes</h3>
<p>create file <strong>routes.js</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> {getInstanceRouter} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"xpresser"</span>);
<span class="hljs-keyword">const</span> router = getInstanceRouter();

router.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">"Hello World"</span>);
router.get(<span class="hljs-string">'/about'</span>, <span class="hljs-function"><span class="hljs-params">http</span> =&gt;</span> http.send({
     <span class="hljs-attr">url</span>: http.req.url
}));
</code></pre>
<p>Re-run <code>node server.js</code> and visit <strong>/</strong> and <strong>/about</strong></p>
]]></content:encoded></item></channel></rss>