<?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>FeathersJS on Techformist</title>
    <link>https://techformist.com/tags/feathersjs/</link>
    <description>Recent content in FeathersJS 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, 22 Apr 2020 06:30:00 +0000</lastBuildDate><atom:link href="https://techformist.com/tags/feathersjs/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Learn FeathersJS by Building a Simple CRM - Client App</title>
      <link>https://techformist.com/learn-feathersjs-realworld-client-app/</link>
      <pubDate>Wed, 22 Apr 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/learn-feathersjs-realworld-client-app/</guid>
      <description>&lt;p&gt;Here we see how to build a real-world client application for your FeathersJS backend. We will use Vue + Feathers-Vuex and quickly create the frontend app.&lt;/p&gt;
&lt;h2 id=&#34;building-the-client-application&#34;&gt;Building the Client Application&lt;/h2&gt;
&lt;p&gt;Previously you saw how we could &lt;a href=&#34;https://techformist.com/learn-feathersjs-build-app/&#34;&gt;use Feathers to quickly build a backend application&lt;/a&gt;. The beauty of feathers is not only that it is quick to build, but it is also universal.&lt;/p&gt;
&lt;p&gt;We can use FeathersJS and Feathers-Vuex (our choice of client storage) to conjure up a client application that totally blows away our users.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Here we see how to build a real-world client application for your FeathersJS backend. We will use Vue + Feathers-Vuex and quickly create the frontend app.</p>
<h2 id="building-the-client-application">Building the Client Application</h2>
<p>Previously you saw how we could <a href="/learn-feathersjs-build-app/">use Feathers to quickly build a backend application</a>. The beauty of feathers is not only that it is quick to build, but it is also universal.</p>
<p>We can use FeathersJS and Feathers-Vuex (our choice of client storage) to conjure up a client application that totally blows away our users.</p>
<p>Our choice of technology for building client -</p>
<ol>
<li>Vue + Feathers-Vuex</li>
<li>Vuetify</li>
</ol>
<h2 id="client-get-started">Client: Get Started</h2>
<p>This is what we will build for the client..</p>
<p><img loading="lazy" src="/2020/feathersjs-vuex-sample-client-app.gif" type="" alt="feathersjs-vuex-sample-client-app"  /></p>
<p>Let&rsquo;s get started.</p>
<blockquote>
<p>All great things in life starts with Vue CLI.</p>
</blockquote>
<p>But, we don&rsquo;t have the time and this is not a Vue tutorial. So, it&rsquo;s time to work the magic and improve that statement.</p>
<p>So, we change the above quote..</p>
<blockquote>
<p>A few great things start with boilerplates.</p>
</blockquote>
<p>Unfortunately, again, we don&rsquo;t quite have a starter-friendly boilerplate. We can either start from our <a href="https://github.com/techformist/vue-vuetify-api-boost.git">vue-vuetify-booster</a> boilerplate, or start afresh.</p>
<p>Either ways your Vue application should be setup in the <code>client</code> folder that is adjacent to the <code>server</code> folder where FeathersJS server resides. We will get our design inspiration from the above boilerplate.</p>
<ul>
<li>Panel / Subpanel etc. are layouts defined in that boilerplate - we will reuse them</li>
<li>There are a few useful ways shortcuts to show snackbar, alerts etc, which we carry forward to this project</li>
<li>The home page, toolbar and navigation drawers will remain largely unchanged except for the links</li>
</ul>
<p>See the <a href="https://github.com/techformist/featherlight-crm">Github repository for Featherlight CRM</a> when in doubt.</p>
<p>At a high level, the client <code>package.json</code> has -</p>
<ol>
<li>Vue + Vuetify</li>
<li>FeathersJS recommended packages. We will use communication over socket.io (alternatively we can use REST, but real-time using socket is more exciting)
<pre tabindex="0"><code>npm i @feathersjs/feathers @feathersjs/rest-client @feathersjs/authentication-client @vue/composition-api feathers-vuex feathers-hooks-common --save
</code></pre></li>
</ol>
<p>Add/modify <code>transpileDependencies</code> line to your <code>vue.config.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">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="c1">// code
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">transpileDependencies</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;vuetify&#34;</span><span class="p">,</span> <span class="s2">&#34;feathers-vuex&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// more code
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Add a new file <code>feathers-client.js</code> to implement feathers client -</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">import</span> <span class="nx">feathers</span> <span class="nx">from</span> <span class="s2">&#34;@feathersjs/feathers&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">auth</span> <span class="nx">from</span> <span class="s2">&#34;@feathersjs/authentication-client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">feathersVuex</span> <span class="nx">from</span> <span class="s2">&#34;feathers-vuex&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">socketio</span> <span class="nx">from</span> <span class="s2">&#34;@feathersjs/socketio-client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">io</span> <span class="nx">from</span> <span class="s2">&#34;socket.io-client&#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">iff</span><span class="p">,</span> <span class="nx">discard</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;feathers-hooks-common&#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">socket</span> <span class="o">=</span> <span class="nx">io</span><span class="p">(</span><span class="s2">&#34;http://localhost:3030&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">transports</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;websocket&#34;</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">const</span> <span class="nx">feathersClient</span> <span class="o">=</span> <span class="nx">feathers</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="nx">socketio</span><span class="p">(</span><span class="nx">socket</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="nx">auth</span><span class="p">({</span> <span class="nx">storage</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">localStorage</span> <span class="p">}))</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">hooks</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">before</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">all</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="nx">iff</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">[</span><span class="s2">&#34;create&#34;</span><span class="p">,</span> <span class="s2">&#34;update&#34;</span><span class="p">,</span> <span class="s2">&#34;patch&#34;</span><span class="p">].</span><span class="nx">includes</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nx">method</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">          <span class="nx">discard</span><span class="p">(</span><span class="s2">&#34;__id&#34;</span><span class="p">,</span> <span class="s2">&#34;__isTemp&#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><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">export</span> <span class="k">default</span> <span class="nx">feathersClient</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Setting up feathers-vuex
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">makeServicePlugin</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">makeAuthPlugin</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">BaseModel</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">models</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">FeathersVuex</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="o">=</span> <span class="nx">feathersVuex</span><span class="p">(</span><span class="nx">feathersClient</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">serverAlias</span><span class="o">:</span> <span class="s2">&#34;api&#34;</span><span class="p">,</span> <span class="c1">// optional for working with multiple APIs (this is the default value)
</span></span></span><span class="line"><span class="cl">  <span class="nx">idField</span><span class="o">:</span> <span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="c1">// Must match the id field in your database table/collection
</span></span></span><span class="line"><span class="cl">  <span class="nx">whitelist</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;$regex&#34;</span><span class="p">,</span> <span class="s2">&#34;$options&#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="kr">export</span> <span class="p">{</span> <span class="nx">makeAuthPlugin</span><span class="p">,</span> <span class="nx">makeServicePlugin</span><span class="p">,</span> <span class="nx">BaseModel</span><span class="p">,</span> <span class="nx">models</span><span class="p">,</span> <span class="nx">FeathersVuex</span> <span class="p">};</span>
</span></span></code></pre></div><p>You should now be able to run the application without issues..</p>
<pre tabindex="0"><code>npm run serve
</code></pre><h2 id="router">Router</h2>
<p>Not a lot of interesting things here.. We just define a dynamic home to redirect users to dashboard or to the generic home page. Everything else is pretty standard.</p>
<p>Note that we have not implemented any navigation guards - but that is easy enough to do by uncommenting the <code>requireAuth</code> function and using that for the routes that need prior authentication.</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">import</span> <span class="nx">Vue</span> <span class="nx">from</span> <span class="s2">&#34;vue&#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">import</span> <span class="nx">store</span> <span class="nx">from</span> <span class="s2">&#34;../store/index&#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">import</span> <span class="nx">VueRouter</span> <span class="nx">from</span> <span class="s2">&#34;vue-router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Home</span> <span class="nx">from</span> <span class="s2">&#34;../views/Home.vue&#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">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">VueRouter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// function requireAuth(to, from, next) {
</span></span></span><span class="line"><span class="cl"><span class="c1">//   if (store.state.auth.accessToken) next();
</span></span></span><span class="line"><span class="cl"><span class="c1">//   else next(&#34;/login&#34;);
</span></span></span><span class="line"><span class="cl"><span class="c1">// }
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">dynamicHome</span><span class="p">(</span><span class="nx">to</span><span class="p">,</span> <span class="nx">from</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// this should be ideally replaced by store.getters[&#34;auth/isAuthenticated&#34;]
</span></span></span><span class="line"><span class="cl">  <span class="c1">// .. in newer versions
</span></span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">store</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">auth</span><span class="p">.</span><span class="nx">accessToken</span><span class="p">)</span> <span class="nx">next</span><span class="p">(</span><span class="s2">&#34;/dashboard&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span> <span class="nx">next</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="kd">function</span> <span class="nx">logout</span><span class="p">(</span><span class="nx">to</span><span class="p">,</span> <span class="nx">from</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">store</span><span class="p">.</span><span class="nx">dispatch</span><span class="p">(</span><span class="s2">&#34;auth/logout&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">next</span><span class="p">(</span><span class="s2">&#34;/login&#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="kr">const</span> <span class="nx">routes</span> <span class="o">=</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">path</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">name</span><span class="o">:</span> <span class="s2">&#34;home&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="nx">Home</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">beforeEnter</span><span class="o">:</span> <span class="nx">dynamicHome</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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/signup&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;signup&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">import</span><span class="p">(</span><span class="cm">/* webpackChunkName: &#34;register&#34; */</span> <span class="s2">&#34;../views/Register.vue&#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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/login&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;login&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">import</span><span class="p">(</span><span class="cm">/* webpackChunkName: &#34;login&#34; */</span> <span class="s2">&#34;../views/Login.vue&#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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/logout&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;logout&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">beforeEnter</span><span class="o">:</span> <span class="nx">logout</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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/terms&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Terms&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">import</span><span class="p">(</span><span class="cm">/* webpackChunkName: &#34;terms&#34; */</span> <span class="s2">&#34;../views/Terms.vue&#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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/dashboard&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Dashboard&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">import</span><span class="p">(</span><span class="cm">/* webpackChunkName: &#34;dashboard&#34; */</span> <span class="s2">&#34;../views/Dashboard.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// beforeEnter: requireAuth
</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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/contacts&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Contact&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Contact.vue&#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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/activities&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Activity&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Activity.vue&#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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/contact-us&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Contact Us&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">import</span><span class="p">(</span><span class="cm">/* webpackChunkName: &#34;contact-us&#34; */</span> <span class="s2">&#34;../views/ContactUs.vue&#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="nx">path</span><span class="o">:</span> <span class="s2">&#34;/about&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;About&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// route level code-splitting
</span></span></span><span class="line"><span class="cl">    <span class="c1">// this generates a separate chunk (about.[hash].js) for this route
</span></span></span><span class="line"><span class="cl">    <span class="c1">// which is lazy-loaded when the route is visited.
</span></span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">import</span><span class="p">(</span><span class="cm">/* webpackChunkName: &#34;about&#34; */</span> <span class="s2">&#34;../views/About.vue&#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="c1">// catch all 404
</span></span></span><span class="line"><span class="cl">    <span class="nx">path</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">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/NotFound.vue&#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">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">VueRouter</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">mode</span><span class="o">:</span> <span class="s2">&#34;history&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">base</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">BASE_URL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">routes</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">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="vuex">Vuex</h2>
<p>Add a new folder called <code>store/services</code> and create <code>users.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">import</span> <span class="nx">feathersClient</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">makeServicePlugin</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">BaseModel</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;../../feathers-client&#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">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="nx">constructor</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">super</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">options</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">// Required for $FeathersVuex plugin to work after production transpile.
</span></span></span><span class="line"><span class="cl">  <span class="kr">static</span> <span class="nx">modelName</span> <span class="o">=</span> <span class="s2">&#34;User&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// Define default properties here
</span></span></span><span class="line"><span class="cl">  <span class="kr">static</span> <span class="nx">instanceDefaults</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">email</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">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="nx">name</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">servicePath</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 class="kr">const</span> <span class="nx">servicePlugin</span> <span class="o">=</span> <span class="nx">makeServicePlugin</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Model</span><span class="o">:</span> <span class="nx">User</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">service</span><span class="o">:</span> <span class="nx">feathersClient</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="nx">servicePath</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">servicePath</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Setup the client-side Feathers hooks.
</span></span></span><span class="line"><span class="cl"><span class="nx">feathersClient</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="nx">servicePath</span><span class="p">).</span><span class="nx">hooks</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">before</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">all</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">find</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">create</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">update</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">patch</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">remove</span><span class="o">:</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">after</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">all</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">find</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">create</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">update</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">patch</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">remove</span><span class="o">:</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">error</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">all</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">find</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">create</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">update</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">patch</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">remove</span><span class="o">:</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">export</span> <span class="k">default</span> <span class="nx">servicePlugin</span><span class="p">;</span>
</span></span></code></pre></div><p>As you see - this is has the familiar structure of FeathersJS. We can fine tune this and change app behaviour, but will leave it that for now.</p>
<p>Create a similar file for <code>contacts</code> - we will use the name <code>contactsPlugin</code> instead of <code>servicePlugin</code>. Rest remains the same.</p>
<p>We will register these plugins in the store.</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">import</span> <span class="nx">Vue</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Vuex</span> <span class="nx">from</span> <span class="s2">&#34;vuex&#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">import</span> <span class="p">{</span> <span class="nx">FeathersVuex</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;../feathers-client&#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">import</span> <span class="nx">snackbar</span> <span class="nx">from</span> <span class="s2">&#34;./snackbar&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">pref</span> <span class="nx">from</span> <span class="s2">&#34;./pref&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">alert</span> <span class="nx">from</span> <span class="s2">&#34;./alert&#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">import</span> <span class="nx">auth</span> <span class="nx">from</span> <span class="s2">&#34;./auth&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">servicePlugin</span> <span class="nx">from</span> <span class="s2">&#34;./services/users&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">contactsPlugin</span> <span class="nx">from</span> <span class="s2">&#34;./services/contacts&#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">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">Vuex</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">FeathersVuex</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="k">new</span> <span class="nx">Vuex</span><span class="p">.</span><span class="nx">Store</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">namespaced</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;global&#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">modules</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">snackbar</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">pref</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">alert</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">auth</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">servicePlugin</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">contactsPlugin</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">plugins</span><span class="o">:</span> <span class="p">[</span><span class="nx">auth</span><span class="p">,</span> <span class="nx">servicePlugin</span><span class="p">,</span> <span class="nx">contactsPlugin</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">state</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">getters</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">isLoggedIn</span><span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="nx">getters</span><span class="p">,</span> <span class="nx">rootState</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="o">!!</span><span class="nx">rootState</span><span class="p">.</span><span class="nx">auth</span><span class="p">.</span><span class="nx">accessToken</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>You will see a few modules not used by feathers - it is just to make the application more pleasing. You can ignore them.</p>
<h2 id="views">Views</h2>
<p>Let us create the <code>Contact</code> view. This is simple and straight forward - we just render the list component here.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">template</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="nx">Panel</span> <span class="nx">icon</span><span class="o">=</span><span class="s2">&#34;mdi-book-plus&#34;</span> <span class="nx">title</span><span class="o">=</span><span class="s2">&#34;Contacts&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">template</span> <span class="nx">slot</span><span class="o">=</span><span class="s2">&#34;toolbar-items&#34;</span><span class="o">&gt;&lt;</span><span class="err">/template&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">template</span> <span class="nx">slot</span><span class="o">=</span><span class="s2">&#34;content&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">ContactList</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/template&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="err">/Panel&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/template&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Panel</span> <span class="nx">from</span> <span class="s2">&#34;../components/layouts/Panel&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">ContactList</span> <span class="nx">from</span> <span class="s2">&#34;../components/ContactList&#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="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Panel</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">ContactList</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="o">&lt;</span><span class="err">/script&gt;</span>
</span></span></code></pre></div><h2 id="contact-view---list-component">Contact View - List Component</h2>
<p>Next, let us create <code>components/ContactList.vue</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">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">PanelListMain</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">template</span> <span class="na">slot</span><span class="o">=</span><span class="s">&#34;toolbar-items&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle-2&#34;</span><span class="p">&gt;</span>Contact List<span class="p">&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">v-spacer</span><span class="p">&gt;&lt;/</span><span class="nt">v-spacer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-btn</span> <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;newRecord&#34;</span> <span class="na">small</span> <span class="na">outlined</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">small</span><span class="p">&gt;</span>mdi-plus<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>New
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">template</span> <span class="na">slot</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">      <span class="p">&lt;</span><span class="nt">v-row</span> <span class="na">dense</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">v-card</span> <span class="na">flat</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;transparent&#34;</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;100%&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;overflow:auto&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">v-card-title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;</span><span class="nt">v-spacer</span><span class="p">&gt;&lt;/</span><span class="nt">v-spacer</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">v-text-field</span>
</span></span><span class="line"><span class="cl">                <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;srchLastName&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="na">prepend-icon</span><span class="o">=</span><span class="s">&#34;mdi-magnify&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="na">label</span><span class="o">=</span><span class="s">&#34;Search Last Name&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="na">single-line</span>
</span></span><span class="line"><span class="cl">              <span class="p">&gt;&lt;/</span><span class="nt">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">v-card-title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">v-data-table</span>
</span></span><span class="line"><span class="cl">              <span class="na">:headers</span><span class="o">=</span><span class="s">&#34;headers&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">:items</span><span class="o">=</span><span class="s">&#34;contacts&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">hide-default-footer</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">template</span> <span class="na">v-slot:item</span><span class="o">=</span><span class="s">&#34;props&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>{{ props.item.first_name }}<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>{{ props.item.last_name }}<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>{{ props.item.title }}<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>{{ props.item.status_cd }}<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>{{ props.item.email }}<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>{{ props.item.phone }}<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;success&#34;</span> <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;editRecord(props.item)&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="p">&gt;</span>mdi-pencil<span class="p">&lt;/</span><span class="nt">v-icon</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">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">v-data-table</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">v-card</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="c">&lt;!-- &lt;v-col cols=&#34;12&#34; class=&#34;text-md-right pt-2&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">          &lt;v-pagination
</span></span></span><span class="line"><span class="cl"><span class="c">            v-model=&#34;contacts.page&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">            :total-visible=&#34;7&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">            :length=&#34;contacts.lastPage&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">            @input=&#34;changePage&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">            justify=&#34;end&#34;
</span></span></span><span class="line"><span class="cl"><span class="c">          &gt;&lt;/v-pagination&gt;
</span></span></span><span class="line"><span class="cl"><span class="c">        &lt;/v-col&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-row</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">ContactEdit</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-if</span><span class="o">=</span><span class="s">&#34;detailDialog&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;detailDialog&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">:currentItem</span><span class="o">=</span><span class="s">&#34;currentItem&#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">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">PanelListMain</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">makeFindMixin</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;feathers-vuex&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">PanelListMain</span> <span class="nx">from</span> <span class="s2">&#34;./layouts/PanelListMain&#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="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">detailDialog</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">headers</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;First Name&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;first_name&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;Last Name&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;last_name&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;Title&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;title&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;Status&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;status_cd&#34;</span><span class="p">,</span> <span class="nx">sortable</span><span class="o">:</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;Email&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;email&#34;</span><span class="p">,</span> <span class="nx">sortable</span><span class="o">:</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;Phone&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;phone&#34;</span><span class="p">,</span> <span class="nx">sortable</span><span class="o">:</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;Actions&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">&#34;actions&#34;</span><span class="p">,</span> <span class="nx">sortable</span><span class="o">:</span> <span class="kc">false</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">srchLastName</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">currentItem</span><span class="o">:</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">computed</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">contactsParams</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">{</span> <span class="nx">query</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">search</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">search</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">srchStr</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">srchLastName</span><span class="p">)</span> <span class="nx">srchStr</span><span class="p">[</span><span class="s2">&#34;last_name&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">srchLastName</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">srchStr</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="nx">mixins</span><span class="o">:</span> <span class="p">[</span><span class="nx">makeFindMixin</span><span class="p">({</span> <span class="nx">service</span><span class="o">:</span> <span class="s2">&#34;contacts&#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">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// changePage(page) {
</span></span></span><span class="line"><span class="cl">      <span class="c1">//   this.fetchContact({
</span></span></span><span class="line"><span class="cl">      <span class="c1">//     page: page,
</span></span></span><span class="line"><span class="cl">      <span class="c1">//     query: this.search,
</span></span></span><span class="line"><span class="cl">      <span class="c1">//   });
</span></span></span><span class="line"><span class="cl">      <span class="c1">// },
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nx">editRecord</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">currentItem</span> <span class="o">=</span> <span class="nx">item</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">detailDialog</span> <span class="o">=</span> <span class="kc">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></span><span class="line"><span class="cl">      <span class="nx">newRecord</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">currentItem</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">detailDialog</span> <span class="o">=</span> <span class="kc">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></span><span class="line"><span class="cl">    <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">PanelListMain</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">ContactEdit</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;./ContactEdit&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>There&rsquo;s a lot going on, but we did not quite put in anything special.</p>
<p>To start with, we introduced ..</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">import</span> <span class="p">{</span> <span class="nx">makeFindMixin</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;feathers-vuex&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">mixins</span><span class="o">:</span> <span class="p">[</span><span class="nx">makeFindMixin</span><span class="p">({</span> <span class="nx">service</span><span class="o">:</span> <span class="s2">&#34;contacts&#34;</span> <span class="p">})],</span>
</span></span></code></pre></div><p>The above code imported and used a feathers provided mixin that makes our coding easier and more generic. We have indicated our intent to use the <code>contacts</code> service - this refers to the service file that we created earlier, which also automatically &ldquo;maps&rdquo; (not exactly, but bear with me) to the <code>contacts</code> service in the backend Feathers.</p>
<p>We create a computed variable which can be used to pass params to the mixin -</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">contactsParams</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span> <span class="nx">query</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">search</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span></code></pre></div><p>By doing just this, we have access to the <code>contacts</code> list. This is the list of contacts fetched from the backend and rendered as a table.</p>
<p>We can change <code>search</code> to pass search criteria. User enters search, and we just pass it as a param in a function.</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">computed</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">search</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">srchStr</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">srchLastName</span><span class="p">)</span> <span class="nx">srchStr</span><span class="p">[</span><span class="s2">&#34;last_name&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">srchLastName</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">srchStr</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>Again.. let me reiterate it for you.</p>
<p>All we did was to add a service, introduced boilerplate code for <code>feathers-client.js</code> and pulled in the mixin. This resulted in the contacts being pulled from the server / from our database.</p>
<p>In addition to what has been outlined so far -</p>
<ol>
<li>We can add functionality with simple param changes on client side and by adding hooks/custom services on server - again a lot of functionality with less code</li>
<li>The app has real-time functions - any changes (on server through API calls / by other users) are published to clients (all clients with default configuration) and our browser starts showing those changes</li>
</ol>
<p>What we did not do -</p>
<ul>
<li>use REST calls with something like fetch/ Axios</li>
<li>manage variables in components / Vuex</li>
<li>create logic to search - on client and server</li>
</ul>
<p>That&rsquo;s a lot of work saved.</p>
<h2 id="contact-edit">Contact Edit</h2>
<p>Let&rsquo;s keep going.</p>
<p>We will add a reference to a new component in <code>ContactList</code> to enable us to edit contacts.</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">ContactEdit</span>
</span></span><span class="line"><span class="cl">  <span class="na">v-if</span><span class="o">=</span><span class="s">&#34;detailDialog&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;detailDialog&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">:currentItem</span><span class="o">=</span><span class="s">&#34;currentItem&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">/&gt;</span>
</span></span></code></pre></div><p>Also, add methods to display this detail component on click of <code>New</code> or <code>Edit</code> buttons.</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">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">editRecord</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">currentItem</span> <span class="o">=</span> <span class="nx">item</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">detailDialog</span> <span class="o">=</span> <span class="kc">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></span><span class="line"><span class="cl">  <span class="nx">newRecord</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">currentItem</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">detailDialog</span> <span class="o">=</span> <span class="kc">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></code></pre></div><p>We set the current item and send it off to <code>ContactEdit</code>.</p>
<p>There are multiple, better ways to invoke <code>ContactEdit</code> to create more elegant/succinct code - we just used on of the options.</p>
<p><code>ContactEdit</code> has some interesting things going on-</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">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-dialog</span> <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;showDialog&#34;</span> <span class="na">persistent</span> <span class="na">max-width</span><span class="o">=</span><span class="s">&#34;1100px&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">SubPanel</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">template</span> <span class="na">slot</span><span class="o">=</span><span class="s">&#34;toolbar-items&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle-2&#34;</span><span class="p">&gt;</span>New/Edit Contact<span class="p">&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">template</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">template</span> <span class="na">slot</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">v-if</span><span class="o">=</span><span class="s">&#34;item&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">FeathersVuexFormWrapper</span> <span class="na">:item</span><span class="o">=</span><span class="s">&#34;item&#34;</span> <span class="na">watch</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">template</span> <span class="na">v-slot</span><span class="o">=</span><span class="s">&#34;{ clone, save, reset, remove }&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">v-form</span> <span class="na">ref</span><span class="o">=</span><span class="s">&#34;form&#34;</span> <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;validInput&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;</span><span class="nt">v-card</span> <span class="na">flat</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">v-card-text</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">v-row</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span> <span class="na">md</span><span class="o">=</span><span class="s">&#34;3&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                      <span class="p">&lt;</span><span class="nt">v-text-field</span> <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;item[&#39;first_name&#39;]&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                      <span class="p">&lt;/</span><span class="nt">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span> <span class="na">md</span><span class="o">=</span><span class="s">&#34;3&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                      <span class="p">&lt;</span><span class="nt">v-text-field</span> <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;item[&#39;last_name&#39;]&#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">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span> <span class="na">md</span><span class="o">=</span><span class="s">&#34;3&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                      <span class="p">&lt;</span><span class="nt">v-select</span>
</span></span><span class="line"><span class="cl">                        <span class="na">:items</span><span class="o">=</span><span class="s">&#34;[&#39;active&#39;, &#39;inactive&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">                        <span class="na">label</span><span class="o">=</span><span class="s">&#34;Status&#34;</span>
</span></span><span class="line"><span class="cl">                        <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;item[&#39;status_cd&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">                        <span class="na">required</span>
</span></span><span class="line"><span class="cl">                      <span class="p">&gt;&lt;/</span><span class="nt">v-select</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;/</span><span class="nt">v-row</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">v-card-text</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">v-card-actions</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">v-spacer</span><span class="p">&gt;&lt;/</span><span class="nt">v-spacer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">v-btn</span> <span class="na">outlined</span> <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;closeDialog&#34;</span><span class="p">&gt;</span>Cancel<span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">v-btn</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;primary&#34;</span> <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;saveRecord&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    Save
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">v-card-actions</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;/</span><span class="nt">v-card</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">v-form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">FeathersVuexFormWrapper</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">SubPanel</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-dialog</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">mapMutations</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vuex&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">SubPanel</span> <span class="nx">from</span> <span class="s2">&#34;./layouts/SubPanel&#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">import</span> <span class="p">{</span> <span class="nx">FeathersVuexFormWrapper</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;feathers-vuex&#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="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">validInput</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">item</span><span class="o">:</span> <span class="kc">null</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="nx">props</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">value</span><span class="o">:</span> <span class="nb">Boolean</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">currentItem</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">type</span><span class="o">:</span> <span class="nb">Object</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">required</span><span class="o">:</span> <span class="kc">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></span><span class="line"><span class="cl">    <span class="nx">mounted</span><span class="p">()</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">Contact</span> <span class="p">}</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">$FeathersVuex</span><span class="p">.</span><span class="nx">api</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">contactModel</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Contact</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">item</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">        <span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">currentItem</span> <span class="o">||</span> <span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">currentItem</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="o">?</span> <span class="nx">contactModel</span>
</span></span><span class="line"><span class="cl">          <span class="o">:</span> <span class="nx">Contact</span><span class="p">.</span><span class="nx">getFromStore</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">currentItem</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 class="nx">computed</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">showDialog</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">get</span><span class="p">()</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">value</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">set</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">$emit</span><span class="p">(</span><span class="s2">&#34;input&#34;</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">SubPanel</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">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span><span class="nx">mapMutations</span><span class="p">(</span><span class="s2">&#34;snackbar&#34;</span><span class="p">,</span> <span class="p">[</span><span class="s2">&#34;setSnack&#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">saveRecord</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="k">this</span><span class="p">.</span><span class="nx">$refs</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">validate</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="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">item</span><span class="p">[</span><span class="s2">&#34;id&#34;</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">item</span><span class="p">.</span><span class="nx">save</span><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">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="k">this</span><span class="p">.</span><span class="nx">showError</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 class="k">else</span> <span class="k">this</span><span class="p">.</span><span class="nx">item</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">closeDialog</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">closeDialog</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">showDialog</span> <span class="o">=</span> <span class="kc">false</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">showError</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="c1">// you can do other housekeeping here.
</span></span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">setSnack</span><span class="p">({</span> <span class="nx">message</span><span class="o">:</span> <span class="s2">&#34;Error saving contact.&#34;</span><span class="p">,</span> <span class="nx">color</span><span class="o">:</span> <span class="s2">&#34;error&#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">error</span><span class="p">(</span><span class="s2">&#34;Error saving record&#34;</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>When the component loads, we specify whether we are creating a new record or editing an existing record.</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">mounted</span><span class="p">()</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">Contact</span> <span class="p">}</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">$FeathersVuex</span><span class="p">.</span><span class="nx">api</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">contactModel</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Contact</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">item</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">      <span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">currentItem</span> <span class="o">||</span> <span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">currentItem</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="o">?</span> <span class="nx">contactModel</span>
</span></span><span class="line"><span class="cl">        <span class="o">:</span> <span class="nx">Contact</span><span class="p">.</span><span class="nx">getFromStore</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">currentItem</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></code></pre></div><p>We fold our form within -</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">FeathersVuexFormWrapper</span> <span class="na">:item</span><span class="o">=</span><span class="s">&#34;item&#34;</span> <span class="na">watch</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">template</span> <span class="na">v-slot</span><span class="o">=</span><span class="s">&#34;{ clone, save, reset, remove }&#34;</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">FeathersVuexFormWrapper</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This code block does quite a few things -</p>
<ol>
<li>Automatically manage vuex best practices to clone our storage variable (<code>item</code> in our case) when necessary. We also indicated support saving, resetting form and removing records</li>
<li>Feathers client automatically maps the record received from the list to the context of the <code>Contact</code> service (either a new record or find existing record from store)</li>
</ol>
<p>Finally, we introduce code to save record -</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">saveRecord</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="k">this</span><span class="p">.</span><span class="nx">$refs</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">validate</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="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">item</span><span class="p">[</span><span class="s2">&#34;id&#34;</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">this</span><span class="p">.</span><span class="nx">item</span><span class="p">.</span><span class="nx">save</span><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">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="k">this</span><span class="p">.</span><span class="nx">showError</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 class="k">else</span> <span class="k">this</span><span class="p">.</span><span class="nx">item</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">closeDialog</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>This code block validates form, and invokes <code>save</code> or <code>update</code> methods supported by our feathers-client to send data to our server. Server Feathers knows the operations from the invoked services and carries out those operations on server.</p>
<p>You may also observe that we did not quite use <code>auth</code> here, but it is implied in the background. Feathers figures out that for us. However, you will observe that we have created the <code>auth</code> module (all of two lines), included it as a plugin in the store, and created components for user registration and login.</p>
<p>That is it - you now have a full fledged.. oh wait.</p>
<p>Remember our previous statement? CRM application is not contacts alone - all of us and our neighbour&rsquo;s dog know that activities make CRM application &ldquo;whole&rdquo;.</p>
<p>That said - I don&rsquo;t want to take away that opportunity of creating a brand new service and Vuex plugin from you. Like the seers of yore, I just point to the direction and you execute all magic, eh?</p>
<h2 id="finis">Finis!</h2>
<p>So here we are then.. A complete.. , er.., 50% complete &ldquo;totally real-world application&rdquo; built using FeathersJS on server and client</p>
<p>It is time for you to spread your wings and fly to newer heights and into the next telephone pole with this knowledge.</p>
<p>I mentioned earlier that the code used here is <a href="https://github.com/techformist/featherlight-crm">available on Github</a> - please don&rsquo;t forget to <code>star</code> the repository. Those stars are what I count sometimes to go to sleep - more the merrier.</p>
<p>Enjoy.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Learn FeathersJS by Building a Simple CRM App</title>
      <link>https://techformist.com/learn-feathersjs-build-app/</link>
      <pubDate>Wed, 08 Apr 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/learn-feathersjs-build-app/</guid>
      <description>&lt;p&gt;We have previously seen a &lt;a href=&#34;https://techformist.com/create-simple-todo-feathersjs/&#34;&gt;simple todo app using FeathersJS&lt;/a&gt;(and NeDB).&lt;/p&gt;
&lt;p&gt;Feathers makes it really easy to develop an API or a real-time app by providing a super-powered baseline that can be extended quickly to create a useful app. However, the example provided earlier does not provide a set of features anywhere near the real-world experience.&lt;/p&gt;
&lt;p&gt;So, here we are talking about all the additional things that Feather could do - only if you let it. This is a FeatherJS + ObjectionJS + Feather-Vuex tutorial through building a totally real-world, simple CRM application called &amp;lsquo;FeatherLight CRM&amp;rsquo;. We name it thus since all awesome apps deserve their own name and identity.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>We have previously seen a <a href="/create-simple-todo-feathersjs/">simple todo app using FeathersJS</a>(and NeDB).</p>
<p>Feathers makes it really easy to develop an API or a real-time app by providing a super-powered baseline that can be extended quickly to create a useful app. However, the example provided earlier does not provide a set of features anywhere near the real-world experience.</p>
<p>So, here we are talking about all the additional things that Feather could do - only if you let it. This is a FeatherJS + ObjectionJS + Feather-Vuex tutorial through building a totally real-world, simple CRM application called &lsquo;FeatherLight CRM&rsquo;. We name it thus since all awesome apps deserve their own name and identity.</p>
<h2 id="our-chosen-ecosystem">Our Chosen Ecosystem</h2>
<p>First, let us get our basic ecosystem right.</p>
<p>Feathers groups together various components and provides more than one component options to do the same job. So, it is that with flutter in my heart, I choose -</p>
<ol>
<li>Postgres - possibly the greatest database of our times</li>
<li>Objection ORM - Benefits of an ORM, and knex for DB migration + operations + low-level query builder</li>
<li>Local authentication</li>
</ol>
<p>Next.. since we love our SPAs and scoff at anything more simple, we choose -</p>
<ol>
<li>Vue + Vuex</li>
<li>Feathers-Vuex (this is the main reason for choosing Vue - makes it a cool developer experience. <code>Feathers</code> and <code>cool</code> - did you get it?)</li>
</ol>
<p>Dealing with all this complexity can spur anxiety, so let us divide the tasks into those required for server and client.</p>
<p>This post primarily deals with server-related tasks, i.e, all things FeathersJS. We will see more of Vue in a subsequent post.</p>
<h2 id="server-get-started">Server: Get Started</h2>
<p>Getting started on Feathers is a breeze and is similar to our earlier project.</p>
<p>Install CLI if you don&rsquo;t have feathers on your computer.</p>
<pre tabindex="0"><code>npm i -global @feathersjs/cli
</code></pre><p>Create the project folder and a client and server folders to store your code.</p>
<pre tabindex="0"><code>mkdir featherlight-crm
cd featherlight-crm
mkdir client
mkdir server
cd server
feathers g app
</code></pre><p>Choose the configuration values for FeathersJS server that talked about five seconds back.
Also, it will be great if you can make the database available at this time - the generator also tries to check for the database.</p>
<p>Open the project folder in your favourite editor - which should be <a href="https://code.visualstudio.com/">VSCode</a> by now.</p>
<p>Once the app generation is complete, open <code>./config/default.json</code> and change the database section to tell knex where migrations need to be stored - both the directories for seed/migrations, and the table in database. This will come in handy in a bit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;postgres&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;client&#34;</span><span class="p">:</span> <span class="s2">&#34;pg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;connection&#34;</span><span class="p">:</span> <span class="s2">&#34;postgres://postgres:@localhost:5432/t_2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;migrations&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;directory&#34;</span><span class="p">:</span> <span class="s2">&#34;../database/migrations&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;tableName&#34;</span><span class="p">:</span> <span class="s2">&#34;knex_migrations&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;seeds&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;directory&#34;</span><span class="p">:</span> <span class="s2">&#34;../database/seeds&#34;</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 your server -</p>
<pre tabindex="0"><code>npm run dev
</code></pre><p>This will not only start the server, but also migrate <code>users</code> (created by our generator) to the database. Note that we did not create migrations for users - ideally we should have done that, but we are crazy enough to want a practical demo of what is possible with Feathers out of the box vs. how our changes impact the way we work.</p>
<p>Login to your DB with your favourite client (which should be <a href="https://www.heidisql.com/">HeidiSQL</a>) to see this table in all its glory.</p>
<p>You can check whether server is running by hitting a few sample end-points in your favourite API client - which should be <a href="https://insomnia.rest/">Insomnia</a>.</p>
<table>
  <thead>
      <tr>
          <th>API</th>
          <th>Result</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GET: http://localhost:3030</td>
          <td>200 OK: Sample feathers HTML</td>
      </tr>
      <tr>
          <td>GET: http://localhost:3030/users</td>
          <td>401 Unauthorized: Not authenticated yet</td>
      </tr>
      <tr>
          <td>POST: http://localhost:3030/users ; <em>input JSON below</em></td>
          <td>200 OK: User created, response JSON with user id</td>
      </tr>
      <tr>
          <td>POST: http://localhost:3030/authentication ; <em>input JSON below</em></td>
          <td>200 OK: User logged in, response JSON with JWT</td>
      </tr>
  </tbody>
</table>
<p>Input messages -</p>
<p><strong>POST: New User</strong></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;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a1@a.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;a1&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>POST: Login</strong></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;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a1@a.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;a1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;strategy&#34;</span><span class="p">:</span> <span class="s2">&#34;local&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>That is it - you have your baseline beautiful project ready.</p>
<h2 id="server-folder-structure">Server: Folder Structure</h2>
<p>Before we proceed, we will have &ldquo;more words&rdquo; on the setup.</p>
<p>FeathersJS is straightforward and does not believe in magic. The folder structure reflects that. Some of the key folders along with their functions are outlined below.</p>
<table>
  <thead>
      <tr>
          <th>Folder Name</th>
          <th>What it contains?</th>
          <th>Function</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>config</td>
          <td>Configuration files for prod &amp; non-prod environments</td>
          <td>Provides config values and parameters including server address/port, DB connection strings, auth mechanism, etc.</td>
      </tr>
      <tr>
          <td>public</td>
          <td>Any files available to the external world</td>
          <td>Typical server implementations use some kind of reverse proxy to expose public files to the outside world</td>
      </tr>
      <tr>
          <td>src</td>
          <td>All source code</td>
          <td>Key files: <code>app</code>, <code>authentication</code>, <code>knex</code>, <code>objection</code></td>
      </tr>
      <tr>
          <td>src/models</td>
          <td>All models</td>
          <td>DB models ready to be migrated</td>
      </tr>
      <tr>
          <td>src/services</td>
          <td>Services are at the heart of Feathers</td>
          <td>Individual folders for users and other services. Consists of services and hooks. Hooks also specify routes amongst other things</td>
      </tr>
      <tr>
          <td>test</td>
          <td>Tests for your app</td>
          <td>Automated testing!</td>
      </tr>
  </tbody>
</table>
<p>We have to pay attention to services in some detail.</p>
<p>Services will have folders created for each new service (well, there are exceptions and weird logic - but this is typical ). Services have a couple of things going for them -</p>
<ol>
<li>Feathers maps REST services to the services defined here - you will be able to make out the similarities between the methods supplied by default and the REST service types</li>
<li>Services can also be called on websockets and the same service runs happily</li>
<li>Hooks provide a before/after way of plugging in custom logic for the services</li>
</ol>
<p>We will see much more of this with a practical example below.</p>
<h2 id="server-create-new-functionality">Server: Create new functionality</h2>
<p>Let us create a string of entities and functions around the entity to enable our super CRM app.</p>
<h3 id="create-contact-service">Create contact service</h3>
<p>It may be a good idea to stop your feathers service at this time. Now, use feathers generate command to create a new service.</p>
<pre tabindex="0"><code>feathers g service
</code></pre><p>Answer the questions to create a new service called <code>contacts</code>. You can select the same <code>Objection</code> as data source as that chosen while creating the app.</p>
<p>This does some useful things -</p>
<ul>
<li>create 3 files under <code>src/services/contacts/</code> - service, hooks and class</li>
<li>create a sample test for <code>contacts</code></li>
<li>create <code>contacts.model</code> in <code>./src/models/</code></li>
<li>update <code>services/index</code> with the new <code>contacts</code> service</li>
</ul>
<p>If you had the feathers server running, <code>contacts</code> table will get created with the default columns specified in <code>contacts.model</code>. We stopped the service since we don&rsquo;t want that.</p>
<p>As you can see -</p>
<ul>
<li>the new structure for <code>contacts</code> is straight-forward and similar to our <code>users</code> example above.</li>
<li>By just running the CLI, you now have the entire <code>contacts</code> service + model setup.</li>
</ul>
<h2 id="the-art-of-models-and-migration">The Art of Models and Migration</h2>
<p>Open <code>src/models/contacts.model.js</code>. Add your own fields, and remove logic to migrate tables.</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">// See https://vincit.github.io/objection.js/#models
</span></span></span><span class="line"><span class="cl"><span class="c1">// for more of what you can do here.
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">Model</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;objection&#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">class</span> <span class="nx">contacts</span> <span class="kr">extends</span> <span class="nx">Model</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">static</span> <span class="nx">get</span> <span class="nx">tableName</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;contacts&#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="kr">static</span> <span class="nx">get</span> <span class="nx">jsonSchema</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;last_name&#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">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">first_name</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">maxLength</span><span class="o">:</span> <span class="mi">50</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">last_name</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">maxLength</span><span class="o">:</span> <span class="mi">50</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">title</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">maxLength</span><span class="o">:</span> <span class="mi">25</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">email</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">maxLength</span><span class="o">:</span> <span class="mi">100</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">phone</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">maxLength</span><span class="o">:</span> <span class="mi">25</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">status_cd</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">enum</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;active&#34;</span><span class="p">,</span> <span class="s2">&#34;disabled&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">          <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;active&#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">address</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">street</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nx">city</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nx">zipCode</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#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><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">$beforeInsert</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">created_at</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">updated_at</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">toISOString</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">$beforeUpdate</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">updated_at</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">toISOString</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">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">app</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// remove the knex table creation code from here
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">contacts</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>While the default <code>contact.model.js</code> is good for initial migration, it becomes tricky to manage future changes. So, we will take the migration statements away from this file, group it elsewhere, and at the same time - streamline migrations.</p>
<p>First, create a file <code>knexfile.js</code> in project root -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./src/app&#34;</span><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">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;postgres&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>Next, install knex command line utility globally. This is useful to manage migrations in this project, and in hundreds of other projects that we will created in the next year.</p>
<pre tabindex="0"><code>npm i -g knex
</code></pre><p>You would have already noticed the <code>config</code> folder in the project root. Make modifications to <code>default.json</code>..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// lot of params/code
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;postgres&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;client&#34;</span><span class="p">:</span> <span class="s2">&#34;pg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;connection&#34;</span><span class="p">:</span> <span class="s2">&#34;postgres://postgres:@localhost:5432/t_2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;migrations&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;tableName&#34;</span><span class="p">:</span> <span class="s2">&#34;knex_migrations&#34;</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="c1">// ...
</span></span></span></code></pre></div><p>The above configuration will set the stage and indicate that a place to store migrations in a DB table called <code>knex_migrations</code> (not created yet).</p>
<p>We are all set. Run knex to create migration files -</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>This will create a template migration file in <code>./database/migrations/</code> folder - something like <code>20200422152442_init.js</code>.</p>
<p>Cut/paste <code>create table</code> statements from the <code>contacts.models.js</code> to this migration file - with a few changes.</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">// ./database/migrations/20200422152442_init.js
</span></span></span><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;contacts&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</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">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">timestamp</span><span class="p">(</span><span class="s2">&#34;created_at&#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">timestamp</span><span class="p">(</span><span class="s2">&#34;updated_at&#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">string</span><span class="p">(</span><span class="s2">&#34;first_name&#34;</span><span class="p">,</span> <span class="mi">50</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;last_name&#34;</span><span class="p">,</span> <span class="mi">50</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;title&#34;</span><span class="p">,</span> <span class="mi">25</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;email&#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="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;phone&#34;</span><span class="p">,</span> <span class="mi">25</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;status_c&#34;</span><span class="p">).</span><span class="nx">defaultTo</span><span class="p">(</span><span class="s2">&#34;active&#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="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="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;contacts&#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 take a deep breath and migrate the table to database.</p>
<pre tabindex="0"><code>knex migrate:latest
</code></pre><p>Check in your database to find <code>contacts</code> table.</p>
<p>But then, while still holding on to the breath, you realise a mistake. There has been one of the hardest typo mistakes that can ever be - <code>status_cd</code> is wrongly input as <code>status_c</code>.</p>
<p>No problem, let us change that.</p>
<pre tabindex="0"><code>knex migrate:rollback
</code></pre><p>.. and ta da - the <code>contacts</code> table is gone from the DB.</p>
<p>Re-run migration -</p>
<pre tabindex="0"><code>knex migrate:latest
</code></pre><p>Did you start breathing again? Well, good for you - that was just in time to realise another miss. You never added <code>address</code> - tis&rsquo; a good thing we are still learning here and not doing a multi-million dollar project. We can always do this later.</p>
<p>Congratulations on completing the database tasks.</p>
<h2 id="back-to-the-server">Back to the Server</h2>
<p>Start your server again ..</p>
<pre tabindex="0"><code>npm run dev
</code></pre><p>You can start doing your REST calls without writing any code to handle <code>contacts</code> transactions -</p>
<p><strong>1. POST http://localhost:3030/contacts</strong></p>
<p>Input -</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;first_name&#34;</span><span class="p">:</span> <span class="s2">&#34;abc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;last_name&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Don&rsquo;t forget to provide token from the authentication/login call done earlier as a <code>bearer</code> token.</p>
<p>Output -</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;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;created_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-22T10:59:03.265Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;updated_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-22T10:59:03.265Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;first_name&#34;</span><span class="p">:</span> <span class="s2">&#34;abc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;last_name&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;phone&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;status_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;active&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>A new contact called <code>abc 1</code> is created.</p>
<p><strong>2. GET http://localhost:3030/contacts</strong></p>
<p>Input -</p>
<p>&lt; no input &gt;</p>
<p>Output -</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;total&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;limit&#34;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;skip&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;created_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-22T10:59:03.265Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;updated_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-22T10:59:03.265Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;first_name&#34;</span><span class="p">:</span> <span class="s2">&#34;abc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;last_name&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;phone&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;status_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;active&#34;</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>This is the right time to let out a joyous cry - huzzah!</p>
<h3 id="more-migrations">More migrations</h3>
<p>You have already seen that <code>feathers generate</code> has already created the <code>contacts</code> model. But, what if you want to change the model?</p>
<p>Changing model will imply changes to -</p>
<ul>
<li>model</li>
<li>underlying table</li>
</ul>
<p>Since <code>feathers</code> is just the coordinator here, we will just use the full power of underlying ObjectionJS/knex and migrations as seen previously.</p>
<p>In our case, we demonstrated our careful planning abilities by adding <code>address</code> in our model (yes, this is a mistake. And yes, this is one of the ways of covering up mistakes). So, the model doesn&rsquo;t need to change.</p>
<p>But, we do have to add address to database. We already have two tables created and are in no mood to rollback a second time. Instead, we add incremental changes to the same table.</p>
<p>Let&rsquo;s create another migration file -</p>
<pre tabindex="0"><code>knex migrate:make contact-address
</code></pre><p>Change the migration 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="c1">// ./database/migrations/20200422173242_contact-address.js
</span></span></span><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">table</span><span class="p">(</span><span class="s2">&#34;contacts&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</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">table</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="s2">&#34;address&#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="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="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">knex</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">table</span><span class="p">(</span><span class="s2">&#34;contacts&#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">dropColumn</span><span class="p">(</span><span class="s2">&#34;address&#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></code></pre></div><p>Run migration -</p>
<pre tabindex="0"><code>knex migrate:latest
</code></pre><p>You will now start seeing an <code>address</code> column against <code>contacts</code> table.</p>
<p>Also, you may have already noticed a table called <code>knex_migrations</code> in your database. That table should have two migration records corresponding to the initial migration and the subsequent incremental migration after doing the above tasks for address.</p>
<p>Knex migrations started shining really bright, didn&rsquo;t they?</p>
<h2 id="more-entities-and-functions">More Entities and Functions</h2>
<p>Now that we have walked through an entity and service, and also know how to change them - we can create dozens more with just clicks and copy/paste magic.</p>
<h3 id="change-users">Change Users</h3>
<p>Previously when you saw how easily we could manage database changes - you were left thinking on how <code>users</code> was not included into this fold. Feathers migrated that table for us, and we don&rsquo;t quite have any way to control that migration.</p>
<p>The good news - you can start anytime without a care for the past deeds. You just have to create another migration and repeat the above tasks to create additional columns and manually change the <code>users.models.js</code> file. It does not matter whether <code>users</code> was created initially by feathers or created by hand in the backend.</p>
<p>So, let&rsquo;s do that!</p>
<p>Create migration file -</p>
<pre tabindex="0"><code>knex migrate:make user-enhancements
</code></pre><p>Change the migration 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">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">table</span><span class="p">(</span><span class="s2">&#34;users&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</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">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;role_cd&#34;</span><span class="p">,</span> <span class="mi">50</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;status_cd&#34;</span><span class="p">,</span> <span class="mi">50</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">date</span><span class="p">(</span><span class="s2">&#34;start_date&#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">date</span><span class="p">(</span><span class="s2">&#34;end_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="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="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">table</span><span class="p">(</span><span class="s2">&#34;users&#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">dropColumn</span><span class="p">(</span><span class="s2">&#34;role_cd&#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">dropColumn</span><span class="p">(</span><span class="s2">&#34;status_cd&#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">dropColumn</span><span class="p">(</span><span class="s2">&#34;start_date&#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">dropColumn</span><span class="p">(</span><span class="s2">&#34;end_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></code></pre></div><p>Run migration -</p>
<pre tabindex="0"><code>knex migrate:latest
</code></pre><h3 id="add-activities-modelservice">Add Activities Model/Service</h3>
<p>It is time to upgrade our app - a CRM app cannot be as simple as having <code>users</code> and <code>contacts</code>. Everyone knows that it is the <code>activities</code> that complete CRM.</p>
<p>By now, you will probably be scoffing and guffawing at adding a new service.</p>
<pre tabindex="0"><code>feathers g service
</code></pre><p>Name this new service <code>activities</code>, and select all the right options.</p>
<p>Change <code>activities.model.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="c1">// See https://vincit.github.io/objection.js/#models
</span></span></span><span class="line"><span class="cl"><span class="c1">// for more of what you can do here.
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">Model</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;objection&#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">class</span> <span class="nx">activities</span> <span class="kr">extends</span> <span class="nx">Model</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">static</span> <span class="nx">get</span> <span class="nx">tableName</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;activities&#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="kr">static</span> <span class="nx">get</span> <span class="nx">jsonSchema</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;type_cd&#34;</span><span class="p">,</span> <span class="s2">&#34;status_cd&#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">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">text</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">description</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">maxLength</span><span class="o">:</span> <span class="mi">255</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">type_cd</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">enum</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;Task&#34;</span><span class="p">,</span> <span class="s2">&#34;Call&#34;</span><span class="p">,</span> <span class="s2">&#34;Meeting&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">          <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;Task&#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">status_cd</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="kr">enum</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;Created&#34;</span><span class="p">,</span> <span class="s2">&#34;Planned&#34;</span><span class="p">,</span> <span class="s2">&#34;In Progress&#34;</span><span class="p">,</span> <span class="s2">&#34;Closed&#34;</span><span class="p">,</span> <span class="s2">&#34;Cancelled&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">          <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;Created&#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">start_date</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;timestamp&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">end_date</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;timestamp&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">due_date</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;timestamp&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">duration</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;integer&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">contact_id</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;integer&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">user_id</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;integer&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">remarks</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;text&#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><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">$beforeInsert</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">created_at</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">updated_at</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">toISOString</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">$beforeUpdate</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">updated_at</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">toISOString</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">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">activities</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Create a migration template for activities -</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">knex</span> <span class="nx">migrate</span><span class="o">:</span><span class="nx">make</span> <span class="nx">activities</span>
</span></span></code></pre></div><p>Change <code>20200422192555_activities.js</code> (the comparative migration file created for you in <code>database/migrations</code> folder) -</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;activities&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</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">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">timestamp</span><span class="p">(</span><span class="s2">&#34;created_at&#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">timestamp</span><span class="p">(</span><span class="s2">&#34;updated_at&#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">integer</span><span class="p">(</span><span class="s2">&#34;contact_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">integer</span><span class="p">(</span><span class="s2">&#34;user_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">string</span><span class="p">(</span><span class="s2">&#34;type_cd&#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="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;status_cd&#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="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;description&#34;</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">table</span><span class="p">.</span><span class="nx">timestamp</span><span class="p">(</span><span class="s2">&#34;start_date&#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">timestamp</span><span class="p">(</span><span class="s2">&#34;end_date&#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">timestamp</span><span class="p">(</span><span class="s2">&#34;due_date&#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">integer</span><span class="p">(</span><span class="s2">&#34;duration&#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;remarks&#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="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="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;activities&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>You perform activities and tasks for a contact. So, one contact can have many activities.
Similarly an activity is done by a user. Hence, we can smartly conclude that activities are related to both users and contacts.</p>
<p>We have played things well and already created <code>contact_id</code>, <code>user_id</code> columns in our <code>activities</code> table. We can also establish the relationship at the model level.</p>
<p>Insert the below code block before <code>$beforeInsert()</code> in <code>activities.model.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></span><span class="line"><span class="cl"><span class="c1">//.. other code
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">static</span> <span class="nx">get</span> <span class="nx">relationMappings</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">User</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./users.model&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">Contact</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./contacts.model&#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">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">owner</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">relation</span><span class="o">:</span> <span class="nx">Model</span><span class="p">.</span><span class="nx">BelongsToOneRelation</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">modelClass</span><span class="o">:</span> <span class="nx">User</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">join</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">from</span><span class="o">:</span> <span class="s2">&#34;activities.user_id&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">to</span><span class="o">:</span> <span class="s2">&#34;users.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 class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">contact</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">relation</span><span class="o">:</span> <span class="nx">Model</span><span class="p">.</span><span class="nx">BelongsToOneRelation</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">modelClass</span><span class="o">:</span> <span class="nx">Contact</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">join</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">from</span><span class="o">:</span> <span class="s2">&#34;activities.contact_id&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">to</span><span class="o">:</span> <span class="s2">&#34;contacts.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 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="c1">//.. more code
</span></span></span></code></pre></div><p>You can see a pattern emerging here, don&rsquo;t you? Objection and Knex make it quite easy to establish and manage relationships. (In this case, however, note that we did not tell the DB that <code>contact_id</code> or <code>user_id</code> are foreign key fields - that can be easily fixed in the migration files).</p>
<p>You can start performing <code>activity</code> requests.</p>
<ul>
<li>
<p>POST http://localhost:3030/activities</p>
<p>&lt; input and output are the same :) &gt;</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;type_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;Meeting&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;status_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;Cancelled&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;contact_id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;user_id&#34;</span><span class="p">:</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>
<p>GET http://localhost:3030/activities</p>
<p>&lt; no input data &gt;</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;total&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;limit&#34;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;skip&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;Meeting&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;status_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;Cancelled&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;start_date&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;end_date&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;due_date&#34;</span><span class="p">:</span> <span class="kc">null</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="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;created_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-23T04:39:09.182Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;updated_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-23T04:39:09.182Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</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></li>
</ul>
<p>Since you already established relationship and storing <code>contact</code> you may also want contact to be fetched along with <code>activity</code> details. We established the relationship by changing <code>activity.model.js</code> but did not tell feathers to get contact details.</p>
<p>That&rsquo;s quite easy to do and requires two steps.</p>
<p><strong>Step 1: Change <code>activities.service.js</code></strong></p>
<p>We tell feathers to allow &ldquo;eager&rdquo; loading of contact details. Change <code>options</code> value in activity service.</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">options</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Model</span><span class="o">:</span> <span class="nx">createModel</span><span class="p">(</span><span class="nx">app</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">paginate</span><span class="o">:</span> <span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;paginate&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">whitelist</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;$eager&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">allowedEager</span><span class="o">:</span> <span class="s2">&#34;[contact]&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p><strong>Step 2: Change <code>activities.hooks.js</code></strong></p>
<p>We will do more than just query for the related contacts -</p>
<ol>
<li>Use <code>find</code> hook to <code>$select</code> only some fields to include in the result</li>
<li>Allow feathers to eager load contact - <code>$eager: &quot;contact&quot;</code></li>
<li>Sort results by <code>created_at (desc)</code> - <code>$sort: { created_at: -1 }</code></li>
<li>Filter activities by owner if the logged in user is not an admin - <code>if (!isAdmin(context)) query[&quot;user_id&quot;] = context.params.user.id;</code></li>
</ol>
<p>These changes are more or less self-explanatory - you can just see the super powers of feathers tumbling out one after the other.</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="p">{</span> <span class="nx">authenticate</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;@feathersjs/authentication&#34;</span><span class="p">).</span><span class="nx">hooks</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">isAdmin</span> <span class="o">=</span> <span class="p">(</span><span class="nx">context</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">return</span> <span class="nx">context</span><span class="p">.</span><span class="nx">app</span><span class="p">.</span><span class="nx">settings</span><span class="p">.</span><span class="nx">appconf</span><span class="p">.</span><span class="nx">admin_roles</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nx">context</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">role_cd</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">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">before</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">all</span><span class="o">:</span> <span class="p">[</span><span class="nx">authenticate</span><span class="p">(</span><span class="s2">&#34;jwt&#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">find</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="kr">async</span> <span class="p">(</span><span class="nx">context</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">query</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">$select</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;type_cd&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;status_cd&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;start_date&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;end_date&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;due_date&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;description&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;created_at&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;updated_at&#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">$eager</span><span class="o">:</span> <span class="s2">&#34;contact&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">$sort</span><span class="o">:</span> <span class="p">{</span> <span class="nx">created_at</span><span class="o">:</span> <span class="o">-</span><span class="mi">1</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">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isAdmin</span><span class="p">(</span><span class="nx">context</span><span class="p">))</span> <span class="nx">query</span><span class="p">[</span><span class="s2">&#34;user_id&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="nx">context</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">context</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">query</span> <span class="o">=</span> <span class="p">{</span> <span class="p">...</span><span class="nx">context</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">query</span><span class="p">,</span> <span class="p">...</span><span class="nx">query</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">context</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="nx">get</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">create</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="kr">async</span> <span class="p">(</span><span class="nx">context</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">// populate user as logged in user by default
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isAdmin</span><span class="p">(</span><span class="nx">context</span><span class="p">))</span> <span class="nx">context</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">user_id</span> <span class="o">=</span> <span class="nx">context</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">context</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="nx">update</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">patch</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">remove</span><span class="o">:</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">after</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">all</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">find</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">create</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">update</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">patch</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">remove</span><span class="o">:</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">error</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">all</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">find</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">get</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">create</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">update</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">patch</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">remove</span><span class="o">:</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>If you don&rsquo;t want to pass <code>context</code> everywhere (e.g. <code>isAdmin(context)</code>), you should totally checkout <a href="https://hooks-common.feathersjs.com/overview.html"><code>hooks-common</code></a>.</p>
<p>After these changes, it is time to get a different response when querying <code>activities</code> -</p>
<p>GET http://localhost:3030/activities</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;total&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;limit&#34;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;skip&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;Meeting&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;status_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;Cancelled&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;start_date&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;end_date&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;due_date&#34;</span><span class="p">:</span> <span class="kc">null</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="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;created_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-23T04:39:09.182Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;updated_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-23T04:39:09.182Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;contact&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;created_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-22T10:57:37.957Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;updated_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2020-03-22T10:57:37.957Z&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;first_name&#34;</span><span class="p">:</span> <span class="s2">&#34;abc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;last_name&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;phone&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;status_cd&#34;</span><span class="p">:</span> <span class="s2">&#34;active&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;address&#34;</span><span class="p">:</span> <span class="kc">null</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You can create more than one record to test sort order and filter conditions.</p>
<h2 id="finis">Finis</h2>
<p>That is it!</p>
<p>We now have the server-side of a totally real-world CRM application ready -</p>
<ol>
<li>Store users, contacts and activities</li>
<li>Ability to register and login</li>
<li>Secured data access by filtering activities by owner</li>
</ol>
<p>If you are stuck anywhere, you could always check your code against the <a href="https://github.com/techformist/featherlight-crm">featherlight-crm repository</a>.</p>
<p>Excited about this CRM application and can&rsquo;t wait to start using it? Onwards to the next phase and <a href="/learn-feathersjs-realworld-client-app">developing a FeathersJS client application on Vue</a>!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Unlock FeathersJS power with a todo client</title>
      <link>https://techformist.com/unlock-feathersjs-power-todo-client/</link>
      <pubDate>Thu, 29 Aug 2019 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/unlock-feathersjs-power-todo-client/</guid>
      <description>&lt;p&gt;Create a simple to-do client using FeathersJS.&lt;/p&gt;
&lt;p&gt;We saw a &lt;a href=&#34;https://techformist.com/create-simple-todo-feathersjs&#34;&gt;quick tutorial on creating simple FeathersJS API&lt;/a&gt; yesterday. Let&amp;rsquo;s unlock the full power of Feathers by using its client library and consume the API created in the earlier post!&lt;/p&gt;
&lt;h3 id=&#34;install-and-initialize-project&#34;&gt;Install and initialize project&lt;/h3&gt;
&lt;p&gt;We will use plain Javascript and HTML with Feathers client-side library for the purpose of this demonstration.&lt;/p&gt;
&lt;h5 id=&#34;create-html-page&#34;&gt;Create HTML page&lt;/h5&gt;
&lt;p&gt;Create a simple HTML page to include -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a simple input box to enter new to-do&lt;/li&gt;
&lt;li&gt;an element to display to-dos fetched from server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will also include &lt;code&gt;feathers&lt;/code&gt; from CDN.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Create a simple to-do client using FeathersJS.</p>
<p>We saw a <a href="/create-simple-todo-feathersjs">quick tutorial on creating simple FeathersJS API</a> yesterday. Let&rsquo;s unlock the full power of Feathers by using its client library and consume the API created in the earlier post!</p>
<h3 id="install-and-initialize-project">Install and initialize project</h3>
<p>We will use plain Javascript and HTML with Feathers client-side library for the purpose of this demonstration.</p>
<h5 id="create-html-page">Create HTML page</h5>
<p>Create a simple HTML page to include -</p>
<ul>
<li>a simple input box to enter new to-do</li>
<li>an element to display to-dos fetched from server</li>
</ul>
<p>We will also include <code>feathers</code> from CDN.</p>
<p>And, copy over styling and scripts from <a href="https://getbootstrap.com/docs/4.3/layout/grid/">Bootstrap grid</a> and <a href="https://getbootstrap.com/docs/4.3/components/alerts/">components</a>.</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;!-- index.html --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE html&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">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="p">&lt;</span><span class="nt">meta</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;text/html;charset=utf-8&#34;</span> <span class="na">http-equiv</span><span class="o">=</span><span class="s">&#34;Content-Type&#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">content</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span> <span class="na">http-equiv</span><span class="o">=</span><span class="s">&#34;encoding&#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>todof!<span class="p">&lt;/</span><span class="nt">title</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://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">integrity</span><span class="o">=</span><span class="s">&#34;sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#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">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">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container pt-5&#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 col-3&#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>Todof Todos!<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="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;pt-5&#34;</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">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;input-group col-4&#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;inTodo&#34;</span><span class="p">&gt;&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></span><span class="line"><span class="cl">            <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">class</span><span class="o">=</span><span class="s">&#34;form-control&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">id</span><span class="o">=</span><span class="s">&#34;inTodo&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;New todo&#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="na">class</span><span class="o">=</span><span class="s">&#34;input-group col-1 &#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">onclick</span><span class="o">=</span><span class="s">&#34;insertTodo()&#34;</span><span class="p">&gt;</span>OK<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><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;row&#34;</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">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pt-5 col-4&#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">id</span><span class="o">=</span><span class="s">&#34;todosNode&#34;</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">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">script</span>
</span></span><span class="line"><span class="cl">      <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://code.jquery.com/jquery-3.3.1.slim.min.js&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">integrity</span><span class="o">=</span><span class="s">&#34;sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">script</span>
</span></span><span class="line"><span class="cl">      <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">integrity</span><span class="o">=</span><span class="s">&#34;sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/@feathersjs/client@^4.3.0/dist/feathers.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;app.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">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>I bet you noticed that we imported script from <code>app.js</code>. That is the script doing all the magic and let&rsquo;s start creating that magic.</p>
<h5 id="initialize-and-configure-feathers">Initialize and configure <code>feathers</code></h5>
<p>Initialize <code>feathers</code>. Create a socket to establish connection and talk to server.</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">// app.js
</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;hello world&#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">socket</span> <span class="o">=</span> <span class="nx">io</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">client</span> <span class="o">=</span> <span class="nx">feathers</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">client</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="nx">feathers</span><span class="p">.</span><span class="nx">socketio</span><span class="p">(</span><span class="nx">socket</span><span class="p">));</span>
</span></span></code></pre></div><h5 id="setup-authentication">Setup authentication</h5>
<p>Configure and call <code>authentication</code> service from server to authenticate user.</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">// app.js
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">client</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;authentication&#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">client</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="nx">feathers</span><span class="p">.</span><span class="nx">authentication</span><span class="p">(</span><span class="nx">config</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">token</span> <span class="o">=</span> <span class="nx">login</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">login</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">auth</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">client</span><span class="p">.</span><span class="nx">authenticate</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">strategy</span><span class="o">:</span> <span class="s2">&#34;local&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">email</span><span class="o">:</span> <span class="s2">&#34;a@test.com&#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;abcde&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">auth</span><span class="p">.</span><span class="nx">accessToken</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">accessToken</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We have hard-coded the user id and password for a quick test - typically that should come from a login form.</p>
<p>Just open <code>index.html</code> in a browser and you should be able to see a nice JSON token in the console.</p>
<h5 id="display-to-dos">Display to-do&rsquo;s</h5>
<p>Include code to fetch and display to-do&rsquo;s.</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">getTodo</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">getTodo</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">todoRecs</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">client</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s2">&#34;todo&#34;</span><span class="p">).</span><span class="nx">find</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="k">this</span><span class="p">.</span><span class="nx">renderList</span><span class="p">(</span><span class="s2">&#34;todosNode&#34;</span><span class="p">,</span> <span class="nx">todoRecs</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">async</span> <span class="kd">function</span> <span class="nx">renderList</span><span class="p">(</span><span class="nx">nodeId</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">nodeId</span><span class="p">).</span><span class="nx">innerHTML</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="kd">let</span> <span class="nx">dataList</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="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">dataList</span> <span class="o">+=</span> <span class="s2">&#34;&lt;li&gt;&#34;</span> <span class="o">+</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="s2">&#34;title&#34;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;&lt;/li&gt;&#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="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">nodeId</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="sb">`&lt;ul&gt;</span><span class="si">${</span><span class="nx">dataList</span><span class="si">}</span><span class="sb">&lt;/ul&gt;`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h5 id="create-to-do">Create to-do</h5>
<p>Tie the input box to the flow. Create new to-do when &lsquo;OK&rsquo; is clicked.</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">async</span> <span class="kd">function</span> <span class="nx">insertTodo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todo is &#34;</span><span class="p">,</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;inTodo&#34;</span><span class="p">).</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todoCreate</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">client</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s2">&#34;todo&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">create</span><span class="p">({</span> <span class="nx">title</span><span class="o">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;inTodo&#34;</span><span class="p">).</span><span class="nx">value</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;todo created&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;inTodo&#34;</span><span class="p">).</span><span class="nx">value</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="k">this</span><span class="p">.</span><span class="nx">getTodo</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="end-result">End result</h3>
<p>Without writing a lot of code, we have -</p>
<ol>
<li>Created a HTML page that talks to our back-end Feathers server</li>
<li>Fetched to-dos and displayed them on the UI</li>
<li>Insert a to-do record without much fuss</li>
</ol>
<p><img loading="lazy" src="/misc/feathersjs-simple-todo-demo.gif" type="" alt="feathersjs-simple-todo-demo"  /></p>
<h3 id="full-code">Full code</h3>
<p>Find all <a href="https://github.com/techformist/todof">code on GitHub</a>.
Here&rsquo;s the full Javascript 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="c1">// app.js
</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;hello world&#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">socket</span> <span class="o">=</span> <span class="nx">io</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">client</span> <span class="o">=</span> <span class="nx">feathers</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">client</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;authentication&#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">client</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="nx">feathers</span><span class="p">.</span><span class="nx">socketio</span><span class="p">(</span><span class="nx">socket</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">client</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="nx">feathers</span><span class="p">.</span><span class="nx">authentication</span><span class="p">(</span><span class="nx">config</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">token</span> <span class="o">=</span> <span class="nx">login</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">getTodo</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">login</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">auth</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">client</span><span class="p">.</span><span class="nx">authenticate</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">strategy</span><span class="o">:</span> <span class="s2">&#34;local&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">email</span><span class="o">:</span> <span class="s2">&#34;a@test.com&#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;abcde&#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="k">return</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">accessToken</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">async</span> <span class="kd">function</span> <span class="nx">getTodo</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">todoRecs</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">client</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s2">&#34;todo&#34;</span><span class="p">).</span><span class="nx">find</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="k">this</span><span class="p">.</span><span class="nx">renderList</span><span class="p">(</span><span class="s2">&#34;todosNode&#34;</span><span class="p">,</span> <span class="nx">todoRecs</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">async</span> <span class="kd">function</span> <span class="nx">renderList</span><span class="p">(</span><span class="nx">nodeId</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">nodeId</span><span class="p">).</span><span class="nx">innerHTML</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="kd">let</span> <span class="nx">dataList</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="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">dataList</span> <span class="o">+=</span> <span class="s2">&#34;&lt;li&gt;&#34;</span> <span class="o">+</span> <span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="s2">&#34;title&#34;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;&lt;/li&gt;&#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="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">nodeId</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="sb">`&lt;ul&gt;</span><span class="si">${</span><span class="nx">dataList</span><span class="si">}</span><span class="sb">&lt;/ul&gt;`</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">async</span> <span class="kd">function</span> <span class="nx">insertTodo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todo is &#34;</span><span class="p">,</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;inTodo&#34;</span><span class="p">).</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todoCreate</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">client</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s2">&#34;todo&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">create</span><span class="p">({</span> <span class="nx">title</span><span class="o">:</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;inTodo&#34;</span><span class="p">).</span><span class="nx">value</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;todo created&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;inTodo&#34;</span><span class="p">).</span><span class="nx">value</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="k">this</span><span class="p">.</span><span class="nx">getTodo</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    
    <item>
      <title>Create a simple to-do API with FeathersJS</title>
      <link>https://techformist.com/create-simple-todo-feathersjs/</link>
      <pubDate>Wed, 28 Aug 2019 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-simple-todo-feathersjs/</guid>
      <description>&lt;p&gt;Create a simple to-do API using FeathersJS v4.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.feathersjs.com/introducing-feathers-4-a-framework-for-real-time-apps-and-rest-apis-afff3819055b&#34;&gt;FeathersJS v4 launched yesterday&lt;/a&gt;, and I wanted to see what changed. Of course, I wasn&amp;rsquo;t going to write a post just about v4 - I have not kept up with the Feathers ecosystem. So, let&amp;rsquo;s refresh our mind and soul by building a quick API and see how the story develops.&lt;/p&gt;
&lt;p&gt;We can start with &lt;a href=&#34;https://github.com/feathersjs/cli&#34;&gt;Feathers using their CLI&lt;/a&gt; or with just a NPM install. We will use feathers CLI for the purpose of this post because of two reasons -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Create a simple to-do API using FeathersJS v4.</p>
<p><a href="https://blog.feathersjs.com/introducing-feathers-4-a-framework-for-real-time-apps-and-rest-apis-afff3819055b">FeathersJS v4 launched yesterday</a>, and I wanted to see what changed. Of course, I wasn&rsquo;t going to write a post just about v4 - I have not kept up with the Feathers ecosystem. So, let&rsquo;s refresh our mind and soul by building a quick API and see how the story develops.</p>
<p>We can start with <a href="https://github.com/feathersjs/cli">Feathers using their CLI</a> or with just a NPM install. We will use feathers CLI for the purpose of this post because of two reasons -</p>
<ul>
<li>the CLI is simply awesome</li>
<li>I am lazy - feathersjs CLI saves a lot of typing</li>
</ul>
<h3 id="install-and-initialize-project">Install and initialize project</h3>
<p>Install Feathers CLI globally.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm install -g @feathersjs/cli
</span></span></code></pre></div><p>Create project.</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">md</span> todof
</span></span><span class="line"><span class="cl"><span class="k">cd</span> todof
</span></span><span class="line"><span class="cl">feathers generate app todof
</span></span></code></pre></div><p>Select defaults for all questions. After the process completes you should have a new project folder (<code>todof</code>) with all packages installed and with an updated <code>package.json</code>.</p>
<p>Explore the project folder in VSCode.</p>
<h3 id="start-coding-an-api">Start coding an API</h3>
<p>Create a new service. A service is an instance of a class and contains all operations for a particular entity.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">feathers g service todo
</span></span></code></pre></div><p><code>feathers g</code> is short for <code>feathers generate</code>.</p>
<p>The command will -</p>
<ul>
<li>create a <code>todo</code> folder and a class, hook and service file within the folder (prefixed by <code>todo.</code>)</li>
<li>create <code>todo.model.js</code> in <code>models</code> folder</li>
<li>register newly created modules</li>
</ul>
<p>Start your server.</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>This will start a feathers server at port 3030 by default.</p>
<h3 id="run-your-new-api">Run your new API</h3>
<p>Go to Insomnia (or your favourite client).</p>
<p>Create a GET request to <code>http://localhost:3030/todo</code></p>
<p>You will receive an 401 error if you had accepted all defaults while creating the service.</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;NotAuthenticated&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;Not authenticated&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;code&#34;</span><span class="p">:</span> <span class="mi">401</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;className&#34;</span><span class="p">:</span> <span class="s2">&#34;not-authenticated&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;errors&#34;</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><h5 id="create-user-and-authenticate">Create user and authenticate</h5>
<p>Let&rsquo;s create a user and use that user to authenticate.</p>
<ol>
<li>Create a POST request to <code>http://localhost:3030/users</code> to create new user</li>
</ol>
<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;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a@test.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;abcde&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><ol>
<li>
<p>Login with the new user. Create a new POST request to <code>http://localhost:3030/authentication</code></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;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a@test.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;abcde&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;strategy&#34;</span><span class="p">:</span> <span class="s2">&#34;local&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
<p>FeathersJS supports JSON authentication. Due to defaults configured for the service and the app itself, we see a default response from authentication request like so -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;accessToken&#34;</span><span class="p">:</span> <span class="s2">&#34;eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyJ9.eyJpYXQiOjE1Njg2OTY3NTMsImV4cCI6MTU2ODc4MzE1MywiYXVkIjoiaHR0cHM6Ly95b3VyZG9tYWluLmNvbSIsImlzcyI6ImZlYXRoZXJzIiwic3ViIjoidFUwTWNwNndFa0xTd1A0ZyIsImp0aSI6IjIxMDViMTVhLTdmMzUtNDA1ZS04NTk2LTQ4MWExNDdiMjNhNCJ9.6JhToJthfiSwtAGXQ7Qwtt4y14ACryvTU0gM9z30AbE&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;authentication&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;strategy&#34;</span><span class="p">:</span> <span class="s2">&#34;local&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;user&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;a@test.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;_id&#34;</span><span class="p">:</span> <span class="s2">&#34;tU0Mcp6wEkLSwP4g&#34;</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>Copy the access token from the response.</p>
<h5 id="createquery-to-do">Create/query to-do</h5>
<p>We will go back to our to-do GET request and include the token. Submit the request again, and you will see the below response -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;total&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;limit&#34;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;skip&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Cool..!</p>
<p>Now, create a to-do record, or two. Create a POST request to <code>http://localhost:3030/todo</code>.</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;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Install feathers&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;completed&#34;</span><span class="p">:</span> <span class="s2">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>These records will be stored in the database we specified while configuring the service. If you accepted defaults, the database will be NeDB (a local datastore) and the data file will be present in <code>&lt;root&gt;/data/</code>.</p>
<p><img loading="lazy" src="/misc/feathers-nedb-folder.jpg" type="" alt="feathers-nedb-folder"  /></p>
<p>Experiment with other services.</p>
<h5 id="update-to-do">Update to-do</h5>
<p>Create a new request - <code>PATCH http://localhost:3030/todo/1pRKub3hU6ft7YNE</code></p>
<p>Note that we used the id received from the earlier GET request in the URL.</p>
<p>Request -</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;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Rule the universe&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Response -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Rule the universe&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;completed&#34;</span><span class="p">:</span> <span class="s2">&#34;false&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1pRKub3hU6ft7YNE&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h5 id="query-single-to-do">Query single to-do</h5>
<p>Create another request - <code>GET http://localhost:3030/todo/1pRKub3hU6ft7YNE</code>.</p>
<p>This request is very similar to the earlier GET but filters the results by applying the id used in URL.</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;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Rule the universe&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;completed&#34;</span><span class="p">:</span> <span class="s2">&#34;false&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1pRKub3hU6ft7YNE&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h5 id="delete-to-do">Delete to-do</h5>
<p>Create yet another request - <code>DELETE http://localhost:3030/todo/1pRKub3hU6ft7YNE</code></p>
<p>Request -</p>
<pre tabindex="0"><code>&lt; no body &gt;
</code></pre><p>Response -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Rule the universe&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;completed&#34;</span><span class="p">:</span> <span class="s2">&#34;false&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1pRKub3hU6ft7YNE&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="take-stock-of-what-you-did-so-far">Take stock of what you did so far</h3>
<p>Looking back - we just used two commands -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">feathers g app todof
</span></span><span class="line"><span class="cl">feathers g service todo
</span></span></code></pre></div><p>And, generated an awesome app that can support all REST operations for the specified entity!</p>
<p>Isn&rsquo;t FeathersJS awesome?</p>
<p>But, don&rsquo;t get teary-eyed yet. Feathers can do a lot more and we will get to those in a while :).</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
