<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Richard Schloss</title>
    <description>The latest articles on Forem by Richard Schloss (@richardeschloss).</description>
    <link>https://forem.com/richardeschloss</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F270477%2F2cbe8bd6-2e8e-450c-a1d2-28d9c92b4086.jpeg</url>
      <title>Forem: Richard Schloss</title>
      <link>https://forem.com/richardeschloss</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/richardeschloss"/>
    <language>en</language>
    <item>
      <title>JS Security Tip 05-01-2024 ICYMI</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Wed, 01 May 2024 16:00:42 +0000</pubDate>
      <link>https://forem.com/richardeschloss/js-security-tip-05-01-2024-icymi-3iho</link>
      <guid>https://forem.com/richardeschloss/js-security-tip-05-01-2024-icymi-3iho</guid>
      <description>&lt;p&gt;Javascript sometimes has its fair share of quirky behavior. I'll keep this one brief and to the point. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;(0)['constructor']['constructor']('return someFunction')&lt;/code&gt; is a way to turn the string argument &lt;code&gt;'return someFunction'&lt;/code&gt; into an actual function that will run; i.e., most likely someone else's script. The expression can be immediately invoked with arguments. For example:&lt;br&gt;
&lt;code&gt;(0)['constructor']['constructor']('return alert')()('hi')&lt;/code&gt; is equivalent to &lt;code&gt;alert('hi')&lt;/code&gt; which will show the popup with message "hi". &lt;/p&gt;

&lt;p&gt;But that's not really the scary part. The scary part is that the entire string can be encoded and obfuscated with brackets (plain-text), so that the following is exactly the same as the above alert statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\"\\"+$.__$+$.__$+$.___+"\\"+$.__$+$.$_$+$.__$+"\\\"\\"+$.$__+$.___+")"+"\"")())();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sequence of brackets looks like it could easily appear anywhere and be mistaken for a byte stream and can easily go unnoticed since it's only 585 bytes. If you do come across a string like this, you'll definitely want to decode it using a tool like this one &lt;a href="https://utf-8.jp/public/jjencode.html"&gt;https://utf-8.jp/public/jjencode.html&lt;/a&gt; to see what it's trying to do.&lt;/p&gt;

&lt;p&gt;This is just another reason why some browsers disallow pasting into the dev console, because even harmless-looking strings can potentially be harmful.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Introducing nuxt-router-ui</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Tue, 22 Jun 2021 21:01:01 +0000</pubDate>
      <link>https://forem.com/richardeschloss/introducing-nuxt-router-ui-b7n</link>
      <guid>https://forem.com/richardeschloss/introducing-nuxt-router-ui-b7n</guid>
      <description>&lt;p&gt;Introducing nuxt-router-ui, a dope AF router UI for Nuxt and VueJS, based on d3. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/i-SOcdJtxGg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Easy-as-pie Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install it
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; nuxt-router-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Nuxt Config (one-line)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;nuxt.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...,&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nuxt-router-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Vue only config
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;your-globals.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;BootstrapVue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap-vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;D3RouterUI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nuxt-router-ui/lib/D3RouterUI.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BootstrapVue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// provides the BModal component&lt;/span&gt;
&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D3RouterUI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;D3RouterUI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Embed it
&lt;/h3&gt;

&lt;p&gt;The component to embed is &lt;code&gt;&amp;lt;D3RouterUI /&amp;gt;&lt;/code&gt;. Find a part of your app that is pretty much fixed, like the footer:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;layouts/default.vue&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nuxt&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;D3RouterUI&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use it
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl + Shift + Space&lt;/td&gt;
&lt;td&gt;Opens Router UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Click (on node)&lt;/td&gt;
&lt;td&gt;Opens the path's children, if any&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl + Click (on node)&lt;/td&gt;
&lt;td&gt;Navigates to that route's path. If it's a parameterized route, you'll be prompted for parameters before navigation (only if parameters are required)*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl + Shift + Click (on node)&lt;/td&gt;
&lt;td&gt;Similar as Ctrl + Click, but force opens the prompt for the parameterized route, whether the parameters are required or not&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(*Note: after parameters are input and submitted, they are cached to localStorage so that you don't have to keep re-entering the parameters.)&lt;/p&gt;

&lt;p&gt;The router UI will always start with the current route's node expanded to show it's children.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mac users
&lt;/h3&gt;

&lt;p&gt;Replace "Ctrl" with "CMD" above. (whatever sets "e.metaKey" and it will work)&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;More complete documentation is hosted &lt;a href="https://nuxt-router-ui.netlify.app/stories/en/Quick%20Start"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A Confession
&lt;/h3&gt;

&lt;p&gt;What this project really is...&lt;/p&gt;

&lt;p&gt;I needed a relatively small project to work on to give me a reasons to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;try a NuxtJS project in full ESM mode. I.e., setting the package type to "module" since that's where the ecosystem is heading.&lt;/li&gt;
&lt;li&gt;try running tests and gaining test coverage on Vue components. &lt;code&gt;require&lt;/code&gt; no longer works, so a bunch of things had to change. This project may serve as my "base project" for future VueJS projects.&lt;/li&gt;
&lt;li&gt;take a component I loved in d3js (the tree) to make it versatile, easily re-usable and framework agnostic, because I'd still want to use this again 10 years from now. &lt;/li&gt;
&lt;li&gt;launch a UI router that was similar to what I worked with in the AngularJS days, but I wanted it to run and look-and-feel based on my preferences. I also wanted it to have enough customizable settings so that in case I changed my mind, I'd only have to tweak settings and never have to really touch the code again. The latest release is v1.0.1. My goal is to not have the codebase get to v1.0.10...wishful thinking maybe?&lt;/li&gt;
&lt;li&gt;help others navigate their routes. Heck, if it helps me out, maybe it'll help others. I wanted this to be a faster solution than having to keep typing in the URL and remembering route parameters. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any of the above bullets were on your learning bucket list, you may wish to check out the source code on my github &lt;a href="https://github.com/richardeschloss/nuxt-router-ui"&gt;repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>nuxt</category>
      <category>d3</category>
    </item>
    <item>
      <title>Introduction to Story-Driven Development with Nuxt Stories</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Wed, 02 Sep 2020 04:34:27 +0000</pubDate>
      <link>https://forem.com/richardeschloss/introduction-to-story-driven-development-with-nuxt-stories-1j33</link>
      <guid>https://forem.com/richardeschloss/introduction-to-story-driven-development-with-nuxt-stories-1j33</guid>
      <description>&lt;p&gt;Develop at the Speed of Thought!&lt;/p&gt;

&lt;p&gt;You want your ideas to come to life as you think of them. The instant you write down those ideas, you demand instant gratification from instant functionality. nuxt-stories is a module that you can use to rapidly write stories, game-plans, notes, documentation, whatever for your Nuxt web application. Actually, if you think about it, even your collection of stories can be your app!&lt;/p&gt;

&lt;p&gt;For the impatient, you may wish to fast-forward directly to the &lt;a href="https://dev.to/richardeschloss/introduction-to-story-driven-development-with-nuxt-stories-1j33#demos"&gt;demos&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Disclaimer: I am the author of &lt;a href="https://www.npmjs.com/package/nuxt-stories"&gt;nuxt-stories&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Almost a year ago, I introduced the world to nuxt-stories 1.x (Nuxt Storybooking: The Painless Way). My first AH-HA moment for simplifying the [traditionally tedious] storybooking workflow came then, when I realized I could simply use the features offered by the web framework: without completely starting from scratch, I could simply extend my application’s routes to show stories when desired and hide them otherwise. A one-line configuration change to save me from a weekend headache.&lt;/p&gt;

&lt;p&gt;Many months later, I had my second AH-HA moment when I realized it was probably the stories I wanted all along to form the application itself, and to not just have them be mere application requirements. I thought stories that could be managed directly on the UI, instead of the filesystem, could allow for a much faster workflow.&lt;/p&gt;

&lt;p&gt;This contrasts significantly to modern web development, where changes are usually made on the filesystem and then those changes are made visible on the UI. The inherent delay in waiting for the filesystem change to manifest itself onto the UI is what I’ve always felt to work against my speed of thought. I needed the arrow to be flipped: to instead have changes made on the UI get automatically saved back to the filesystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mental Breakthrough: We never really wanted apps, we wanted functional stories
&lt;/h2&gt;

&lt;p&gt;It occurred to me that perhaps even though we have all gotten accustomed to using apps, that maybe we never really wanted to use them, but rather functional stories. Stories written on our terms, not anyone else’s. Stories that work with our thought processes and look the way we want. Stories with components organized to our individual liking, instead of apps fragmented on a screen, requiring us to jump in and out of them.&lt;/p&gt;

&lt;p&gt;All of human history has been built on stories: ideas we’ve had, lessons we’ve learned, times where we’ve pivoted, and unique calculations we’ve performed. With so much variation encountered by each individual, how can any one app completely satisfy the needs of any one person? And even if apps completely do what we want, why all the updates? The answer is they don’t and never will, precisely because our needs and wants will change as time goes on.&lt;/p&gt;

&lt;p&gt;Instead, we need stories that we can write, stories that can then interpret what we write to visualize the knowledge we seek, and then adapt as we do. Having stories that contain not just ideas, but also functional components will potentially be the fastest way to bring thought to life. Moreover, when such stories can be written in a format that loosely looks likes most people’s PostIt® notes (i.e., Markdown), then the story writing and even pseudo-coding can be done by a world of people, not just software developers.&lt;/p&gt;

&lt;p&gt;For example, a single story point might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;* The weather in **{{ destination }}**:
&lt;span class="nt"&gt;&amp;lt;weather&lt;/span&gt; &lt;span class="na"&gt;:location=&lt;/span&gt;&lt;span class="s"&gt;"destination"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it would be ideal to see that quickly transform into something like this:&lt;/p&gt;




&lt;p&gt;The weather in &lt;strong&gt;San Francisco&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--per7UIZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/azfxn49t9r1u6mje4bu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--per7UIZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/azfxn49t9r1u6mje4bu2.png" alt="Alt Text" width="647" height="540"&gt;&lt;/a&gt;&lt;br&gt;
(Screenshot of Google Weather; this example would have “destination” set to “San Francisco” in the stories’ reserved data section)&lt;/p&gt;



&lt;p&gt;And then from that point on, this functional widget would always be part of the story. There is complete control of where the widget goes and how it is styled. Ideally, this would all happen as the widget syntax is written down, without the need to go to some app store. The app store would probably be replaced by a component or stories “store”, so that instead of downloading entire apps, just the parts of interest are pulled. Or perhaps even better, widgets could probably have built-in “from” or “variant” attributes that would instantiate a specific widget on-demand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;weather&lt;/span&gt; &lt;span class="na"&gt;from=&lt;/span&gt;&lt;span class="s"&gt;”google”&lt;/span&gt; &lt;span class="na"&gt;location=&lt;/span&gt;&lt;span class="s"&gt;”San&lt;/span&gt; &lt;span class="na"&gt;Francisco&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No store to go to, no waiting for downloads to finish, just retrieve the information of interest the instant the tag is closed with “/&amp;gt;”. No need to hit “Ctrl + Enter” or have some knowledge of keyboard shortcuts. Just type what you want to get what you want.&lt;/p&gt;

&lt;h1&gt;
  
  
  Important Characteristics of Stories
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Stories are constantly changing. Computer code branches all the time precisely because our stories branch. Therefore, a storybooking tool will be most useful when used in conjunction with a version control system such as git, so that the branches can quickly be changed in and out.&lt;/li&gt;
&lt;li&gt;Stories that constantly change require dynamic hosts to listen for those changes. nuxt-stories uses nuxt-socket-io under the hood to accomplish this.&lt;/li&gt;
&lt;li&gt;Stories can constantly change, but sometimes the content is meant to be hosted statically so that others can’t change it. For example, instruction guides or documentation. nuxt-stories allows the static host options to be configured.&lt;/li&gt;
&lt;li&gt;Stories can either be uploaded to a central location or distributed to (and only to) a network of subscribers. The holochain (h-wiki) was the inspiration for the latter.&lt;/li&gt;
&lt;li&gt;Stories and the storybooking tool should be accessible to all, not just those who know how to code. Thus, editing directly on the UI is a non-negotiable requirement. Developing away from the UI in a preferred IDE should also be possible to satisfy those users too. This way, stories that get created on the UI can be saved back to the filesystem, and vice versa.&lt;/li&gt;
&lt;li&gt;All parts of the stories, including the functional ones, should be responsive, as in the instant we write them down. Just like a painter needs to see the stroke as she paints, story tellers need to see the UI widgets come to life as they are written, not 3–4 seconds after the fact. Even a 1 second delay becomes painfully distracting.&lt;/li&gt;
&lt;li&gt;Stories have to be automatically saved after being written down. Long before computers existed, “Ctrl + S” was never a requirement to secure one’s written thought, and, in my opinion, still shouldn’t be. Auto-distributing, on the other, has its own set of requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Stories Organization
&lt;/h1&gt;

&lt;p&gt;In nuxt-stories, stories are organized as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[app root] / [storiesDir; default: “stories”] / [lang; default: “en”]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the demos presented in this article below, the following organization is used:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gRx3Dk6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8la5s5pji3jtdnpl1gqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gRx3Dk6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8la5s5pji3jtdnpl1gqg.png" alt="Alt Text" width="761" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8ScF0__i4tI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As shown above, it is seen that stories can either be written as “Vue-first” or “Markdown-first”. In my personal opinion, “Markdown-first” is much more intuitive and portable, and so all demos introduced here will use that approach. Also, from this point on, the nuxt-stories module will only support add/edit/delete operations on “Markdown-first” stories. I apologize to any version 1 users that got used to “Vue-first” but, I think you’ll like “Markdown-first” more.&lt;/p&gt;

&lt;h1&gt;
  
  
  Demos
&lt;/h1&gt;

&lt;p&gt;For the rest of this article, I’ll let the videos do the talking. I composed them to help your reading pace keep up with my writing pace. You can pause/play/seek the controls to exactly the tidbits you want. This may be the best way to learn exactly what nuxt-stories is all about and what it plans to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Usage
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/myvO23cYJnQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatically-Generated Table of Contents
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/apok3ioB53c"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Inputting Data
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/njkbUIRZ3ls"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Reordering Stories
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/inR-ICj1Iog"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Importing Components
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Y1Eftqe77n0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Updating Calculations
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ti9KGER7Nx4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Fun with Videos
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PXN_Xr75EJQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Important notes
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Since the UI is allowing you to do live editing and real-time compiling, there is technically a lot of rule-breaking going on, but it’s ok, because this is simply a dev tool primarily used locally. Expect to see console log statements going haywire. As you type, naturally, compilation will fail as the component name is incomplete. My best recommendation is to temporarily mute console errors, or disable the “error” log level in dev tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For the markdown-based stories, first the stories get parsed by the markdown parser, and then compiled by the Vue compiler. Whatever is entered in the left pane gets parsed/compiled, so make sure you trust the input. Included with the nuxt-stories module is a DOMpurify package which you may wish to enable for sanitizing the markdown. However, this can impede your workflow. Choose how much speed you want to trade off for security or vice versa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As each individual story grows, parsing and compilation will occur with &lt;em&gt;as you type&lt;/em&gt; and this can result in a slower responsiveness if the story becomes too large. While there is a configurable debounce time help with this, a 300 ms delay between the keystroke and the parsing to be exact, think of this as a way to further improve the organization of your stories. The smaller they are, the easier it may be to organize your thoughts too. It may be planned in the future too to have UI controls that allow for pausing / resuming of live compilation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the UI, there are some features still unimplemented, such as the search box, language selector and user control. In fact, there is still much &lt;a href="https://nuxt-stories.netlify.app/stories/en/Todo"&gt;Todo&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;While version 1 of nuxt-stories was pretty cool, in hindsight, it didn’t quite do all I wanted for a story-driven development. Version 2 has some major improvements, but there is still a lot of work to be done. The bigger takeaway, however, is providing concrete examples of story-driven development so that the concepts can easily be reused and improved upon. In fact, version 2 came about after not only brainstorming ideas for 5 months, but studying from others, such as ObservableHQ, bootstrap-vue, nuxt-content, h-wiki, and even storybookjs. So much respect goes to them too.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to contribute? Code or no code, great ideas improve the project. It’s here: &lt;a href="https://github.com/richardeschloss/nuxt-stories"&gt;https://github.com/richardeschloss/nuxt-stories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Want to connect? Find me on Linkedin here: &lt;a href="https://www.linkedin.com/in/richardeschloss/"&gt;https://www.linkedin.com/in/richardeschloss/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>vue</category>
    </item>
    <item>
      <title>COVID-19 SPC: Statistical Process Control Charts</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Sun, 03 May 2020 20:48:14 +0000</pubDate>
      <link>https://forem.com/richardeschloss/covid-19-spc-statistical-process-control-charts-7b4</link>
      <guid>https://forem.com/richardeschloss/covid-19-spc-statistical-process-control-charts-7b4</guid>
      <description>&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;Just launched (05/03/2020 at 2 AM): I created a web app that helps answer the question "How well is YOUR region doing with regards to COVID-19"? While there are already many great dashboards out there, I just wanted something far simpler: two charts and that's it. Trends of cases and deaths, which can be filtered by state, and further by region. I also wanted &lt;em&gt;just&lt;/em&gt; the data. No opinions, no ads, no bloat, no auto-play videos on the side. Just the data. Unaltered, unbiased. I know people are capable of forming their own opinions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Usage
&lt;/h1&gt;

&lt;p&gt;The web app is currently hosted on Netlify at &lt;a href="https://covid19-spc.netlify.app"&gt;https://covid19-spc.netlify.app&lt;/a&gt; and using it is extremely simple with only two controls: a dropdown for the state and another for the region. Deleting the region or selecting a different state resets the charts to the "state level":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TxFkyDAg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/3dueve125froa7hoxkxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TxFkyDAg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/3dueve125froa7hoxkxa.png" alt="Alt Text" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How it works
&lt;/h1&gt;

&lt;p&gt;The web app takes advantage of the new fetch feature released in Nuxt 2.12, and also uses npm package &lt;a href="http://npmjs.com/package/vue-highcharts"&gt;vue-highcharts&lt;/a&gt; to make setting chart data from a Vue prop straightforward. Normally with the highcharts API, you would have to keep calling &lt;code&gt;.setData({})&lt;/code&gt; to update the series data, but with vue-highcharts, just provide the data; the &lt;code&gt;setData()&lt;/code&gt; calls are handled for you.&lt;/p&gt;

&lt;p&gt;So, for this particular app, there are two main components: 1) TrendChart.vue, and 2) ComboSelect.vue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trend Chart component
&lt;/h2&gt;

&lt;p&gt;In this component, we define the props "dates" (as epoch time), "trendData" (the data points we want to work with). Then the &lt;em&gt;computed&lt;/em&gt; props will change when those props change, with one important computed prop being the "chartOptions" provided to the highcharts component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;computed: {
  dailyIncreases() {
    return Stats.dailyIncreases(this.trendData)
  },
  ...
  chartOptions() {
    return {
      ...
      xAxis: {
          type: 'datetime'
        },
        series: [
          {
            name: 'Daily Increases',
            color: 'purple',
            data: this.dailyIncreases.map((v, idx) =&amp;gt; [this.dates[idx], v])
          },
          ....
        ]
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, when we want to use the component, it's extremely simple:&lt;/p&gt;

&lt;p&gt;pages/index.vue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;trend-chart :dates="casesInfo.dates" :trendData="casesInfo.cases" /&amp;gt;
&amp;lt;trend-chart :dates="deathsInfo.dates" :trendData="casesInfo.deaths" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Combo Select component
&lt;/h2&gt;

&lt;p&gt;This component takes advantage of the HTML datalist component, which allows an input text box to be tied to a list of options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input
        v-model="selectedItem"
        :placeholder="placeholder"
        :list="id"
        class="form-control"
      /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;datalist :id="id"&amp;gt;
      &amp;lt;option v-for="item in items" :key="item" :value="item" /&amp;gt;
    &amp;lt;/datalist&amp;gt;
  &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we use this component, we want "selectedItem" to actually be a bound property in the parent that uses it; i.e., the parent will set it's v-model to "selectedItem". So to get the bound behavior, we need to set "value" as a prop in the component, and make "selectedItem" a &lt;em&gt;computed&lt;/em&gt; prop with a defined getter and setter. Also, since the datalist input needs to be linked to a unique id, we have to make that a property too.&lt;/p&gt;

&lt;p&gt;Inside "components/ComboSelect.vue":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;props: {
  id: { type: String, default: () =&amp;gt; {},
  value: { type: String, default: () =&amp;gt; '' },
  items: { type: Array, default: () =&amp;gt; [] },
  placeholder: { type: String, default: () =&amp;gt; '' }
},
computed: {
  get() {
    return this.value // value is a prop 
  },
  set(val) {
    if (val &amp;amp;&amp;amp; this.items.includes(val)) {
      // When the input changes, and it's an item in the datalist
      // emit "itemSelected" event
      this.$emit('itemSelected', val)
    } else {
      // Otherwise, just send "input" event
      this.$emit('input', val)
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in the page that uses the component, it is extremely simple to re-use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;combo-select 
  v-model="selectedState" 
  :id="stateSelect" 
  :items="states" 
  :placeholder="Select State"
  @itemSelected="stateSelected" /&amp;gt; 
&amp;lt;combo-select
  v-model="selectedRegion"
  :id="regionSelect" 
  :items="regions" 
  placeholder="Select Region"
  @input="regionInput"
  @itemSelected="regionSelected" /&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above snippet, we listen for "regionInput" because when it becomes empty, we can reset the charts back to the state view. An empty string will never trigger the "itemSelected" event.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main page and "fetch"
&lt;/h2&gt;

&lt;p&gt;In Nuxt 2.12, a new fetch has been introduced that allows fetching to be done either on the server or client side, setting the "fetchOnServer" boolean. The new fetch also exposes $fetchState which can tell us "pending" status of the fetch request, as well as the fetch timestamp. The pending boolean gets set to false when the fetch method completes (i.e., it's promises resolve). &lt;/p&gt;

&lt;p&gt;So, this means we can control the displayed "Fetching data..." text like this now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span v-show="$fetchState.pending"&amp;gt;
  (Fetching data...)
&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our script would simply be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch() {
  const urls = [...] // Array of sources
  const p = urls.map(Csv.fetch) // Array of promises to fetch the csv files
  Promise.all(p).then(parse) // When all those promise resolve, parse the data
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Full disclosures
&lt;/h1&gt;

&lt;p&gt;The website uses localStorage, but only to remember your dropdown selections so that you don't have to keep selecting state and region on page refresh. This information does not get sent back to me or third-parties. I don't want that information and I don't want to write the code for that.&lt;/p&gt;

&lt;p&gt;The website uses an ".app" domain, since Netlify moved sites to that. This may or may not be the reason why some websites may incorrectly flag this as spam. Rest assured, it's not. In fact, all the source code is available on my Github &lt;a href="https://github.com/richardeschloss/covid19-spc"&gt;repo&lt;/a&gt; and I encourage people with any concerns to check the code before navigating to the website. In just day 1, we already have a few people cloning it.    &lt;/p&gt;

&lt;p&gt;Also, the web app uses data provided by John's Hopkins University, sourced from their &lt;a href="https://github.com/CSSEGISandData/COVID-19/tree/master/csse_covid_19_data"&gt;Github&lt;/a&gt;. To my knowledge, I believe I am adhering to their terms of use.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>covid19</category>
    </item>
    <item>
      <title>Nuxt Socket.IO: The Magic of Dynamic API Registration</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Fri, 03 Apr 2020 06:21:38 +0000</pubDate>
      <link>https://forem.com/richardeschloss/nuxt-socket-io-the-magic-of-dynamic-api-registration-34df</link>
      <guid>https://forem.com/richardeschloss/nuxt-socket-io-the-magic-of-dynamic-api-registration-34df</guid>
      <description>&lt;p&gt;TL;DR — This one is a long read, but may be worth it. The feature is still very new and perhaps there is still room for improvement, but so far, it is my favorite feature that I wrote for the &lt;a href="https://www.npmjs.com/package/nuxt-socket-io"&gt;nuxt-socket-io&lt;/a&gt; module. The idea in a nutshell is: simply request the API from your server when you need it, and like magic, &lt;em&gt;all&lt;/em&gt; it's supported methods will be there, ready to be used by your app! Also, when the server emits events, the data from those events will magically appear. Just reference the data property you want and it'll be there! And, if you have a client API you wish to share back with the server, you can do that too! R.I.P. API docs!&lt;/p&gt;

&lt;p&gt;The knowledgeable or impatient may wish to skip straight to "Implementation Details"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: I am the author of the &lt;a href="https://www.npmjs.com/package/nuxt-socket-io"&gt;nuxt-socket-io&lt;/a&gt; module&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Prior to reading this article, it is highly recommended for the reader to read my previous articles, which serve as precursors to this one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@richard.e.schloss/rethinking-web-io-c7efbde0657e"&gt;Re-Thinking Web IO&lt;/a&gt; -- Discusses concepts of "emit", "listen" and "broadcast"&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/javascript-in-plain-english/re-thinking-web-apis-to-be-dynamic-and-run-time-adaptable-a1e9fb43cc4?source=your_stories_page---------------------------"&gt;Re-Thinking Web APIs to be Dynamic and Run-Time Adaptable&lt;/a&gt; -- Discusses Dynamic API concepts and what I call "KISS Dynamic API format". That format will be used throughout the article.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the second article, I discuss some of the problems with static application peripheral interfaces (APIs). Namely, whenever a server-side developer changes its API, the client-side developer has to update his code in order for the client-side application to still work. Even if the server allows the client to access older API versions, the client may be missing out on all the benefits the new API offers. &lt;/p&gt;

&lt;p&gt;Normally, when there are server API changes, if the client-side developer wants to use that new API, he must read through lengthy docs and manually update his code in order to use those new methods. This manual process is even more time-consuming if it is the developer's first time interacting with that API or if the changes are grandiose; that is, he must learn a huge set of methods and schemas. The API docs are only as good as the person who can understand them, and it can be easy to overlook fine but important details. Even if this were not the case, it usually feels like a total drag to &lt;em&gt;manually&lt;/em&gt; maintain APIs and the corresponding documentation. &lt;/p&gt;

&lt;p&gt;Since any running instance of code &lt;em&gt;already knows&lt;/em&gt; what it can do, it seems most logical to ask &lt;em&gt;that instance&lt;/em&gt; for &lt;em&gt;its&lt;/em&gt; API instead of referring to some hosted docs. Things would be far more efficient, in my opinion, if the actual server instance communicated its capabilities when an appropriate client asked for them. Likewise, the &lt;em&gt;server&lt;/em&gt; in return may wish to know what that client's capabilities are too, so that it knows what supported events would actually be worth sending or not. This way, no API docs need to be written or read ahead of time, as the actual supported API is communicated &lt;em&gt;on-demand&lt;/em&gt;, and the methods can be created on-the-fly. What are API methods any way? Are they not just emitters of events? For the most part, I'd like to think so. Just use the correct schemas and both sides will be good to go. &lt;/p&gt;

&lt;h2&gt;
  
  
  A small digression
&lt;/h2&gt;

&lt;p&gt;I would like to return to my extreme example from a previous article, involving our beloved astronaut. Let's call her Lena. Suppose Lena left for Mars way back in 2014, but before she left, she had the most perfect app for interacting with Google Finance. Her app used the Google Finance APIs from 2014, and could retreive stock prices, histories, dividends, news, etc. She left for Mars and came back several years later to find out how her portfolio is doing using her beautiful app. What does she find? Her &lt;em&gt;entire app&lt;/em&gt; is broken! Several pretty containers with no data to show! Why? All the APIs changed without her and the server never communicated those changes!&lt;/p&gt;

&lt;p&gt;In order for her to get her app back up into somewhat working order, she now has to familiarize herself will all the new Google APIs, and update all the parts of her code where she is making requests. While her URLs still point to "finance.google.com" she has to change the messages she sends, and maybe even the code for validating the responses. Some responses may be quite incomplete. It would be great if she could just send one request "getAPI" to instantly get the new supported methods ready to be run. While there might still be UI tweaks to be made, this may make it easier for her to adapt to the new changes. The API will be right there for to her to inspect in her browser's dev tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Details
&lt;/h2&gt;

&lt;p&gt;Returning to topic, with a client not having any prior knowledge of a given server (i.e., Lena does not know the &lt;em&gt;new&lt;/em&gt; Google Finance) and with a server not having any prior knowledge of a given client, the problems the nuxt-socket-io module intends to solve are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How can we know what the server's supported methods are at any given time? What are the events it will emit? What format will its messages be in?&lt;/li&gt;
&lt;li&gt;Same question for the client? How do we tell the server what the client can and will do?&lt;/li&gt;
&lt;li&gt;Can the IO server be considered a peer of the client? If so, the client already knows what the peer can do.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's not enough though to just know the answers to above questions for the plugin to be useful. It would be even more helpful if the plugin built out the methods and listeners &lt;em&gt;on demand&lt;/em&gt; and &lt;em&gt;once they are known&lt;/em&gt;. So that if a supported method &lt;code&gt;getQuote&lt;/code&gt; became known, the client could simply run &lt;code&gt;ioApi.getQuote({symbol})&lt;/code&gt; and it would work. Likewise, if the client knows an event &lt;code&gt;priceChanged&lt;/code&gt; will come in, the client can simply just point to &lt;code&gt;ioData.priceChanged&lt;/code&gt;, and the data will be there. No extra manual effort needed to listen for new events.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Few Words of Caution
&lt;/h2&gt;

&lt;p&gt;In order for the plugin to pull off the magic that it does, it requires both sides of the channel to follow the "KISS Dynamic API Format", which I tried to keep as simple as I could. The format is needed so that the plugin knows how to organize data and set things up correctly.&lt;/p&gt;

&lt;p&gt;As a reminder, here is the high-level view of that format:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9z89Z8HG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/lvizj0z519d42c7je08r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9z89Z8HG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/lvizj0z519d42c7je08r.png" alt="Alt Text" width="795" height="858"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The format is expected to be a JSON object containing "label" (optional), "version" (recommended), "evts" (optional), and "methods" (optional). After the plugin successfully receives and registers an API, it will set an additional property: "ready".&lt;/p&gt;

&lt;p&gt;The other word of caution is that the plugin slightly goes against Vue guidelines by using a bit of magic, and not everyone is a fan of magic. However, I can make a case for the magic. It's needed to allow the dynamic behavior to occur, and the magic will only be contained to the "ioApi" and "ioData" properties I'll describe below. &lt;/p&gt;

&lt;p&gt;The plugin has to make use of &lt;code&gt;this.$set&lt;/code&gt; so that the data it assigns can still be reactive. Normally, Vue wants data to be defined up front, which is fine and simple if there is a small set of data, but if the data needs to be changed, especially if it's a large model, manual updates will become quite tedious.&lt;/p&gt;

&lt;p&gt;And, perhaps most important consideration is to make sure you trust your IO servers! If the IO server wanted to be malicious, it could overload your app with unwanted events and messages! (A security model would have to be considered, but is beyond the scope of this article)&lt;/p&gt;
&lt;h1&gt;
  
  
  The $nuxtSocket Vuex Module
&lt;/h1&gt;

&lt;p&gt;As of v1.0.22, the plugin will now register a namespaced Vuex module "$nuxtSocket" if it does not already exist. If planning to use the module, the name "$nuxtSocket" should be considered reserved. Disabling this is discouraged. &lt;/p&gt;

&lt;p&gt;The module will build out the following states which can then be accessed by &lt;code&gt;$store.state.$nuxtSocket[prop]&lt;/code&gt;, where prop is one of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;clientApis&lt;/code&gt;: contains the client apis for each component See the section on client APIs for more details.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ioApis&lt;/code&gt;: contains the server apis for each IO server. See the section on server APIs for more details&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sockets&lt;/code&gt;: contains the persisted sockets, if any. (persistence is discussed in the git repo).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;emitErrors&lt;/code&gt;: contains emit errors that have occurred, organized by the socket label, and then by the emit event.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;emitTimeouts&lt;/code&gt;: contains emit timeouts that have occurred, organized by the socket label and then by the emit event.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even if an API is considered a peer, it will be cached in "ioApis". Beyond the scope of this discussion are the mutations and actions also registered in the vuex module (if interested, refer to the &lt;a href="https://github.com/richardeschloss/nuxt-socket-io"&gt;git repo&lt;/a&gt;). &lt;/p&gt;
&lt;h1&gt;
  
  
  Server API Registration
&lt;/h1&gt;

&lt;p&gt;First recall from the very first article on &lt;a href="https://medium.com/javascript-in-plain-english/introduction-to-nuxt-socket-io-b78c5322d389"&gt;nuxt-socket-io&lt;/a&gt;, sockets are configured in &lt;code&gt;nuxt.config&lt;/code&gt; in a &lt;code&gt;sockets&lt;/code&gt; array, where each entry specifies a socket name and url. This makes it easy to reference the socket throughout the app (using the name). The name is also used for helping organizing APIs. &lt;/p&gt;

&lt;p&gt;As a very simple example, suppose &lt;code&gt;nuxt.config&lt;/code&gt; contained the following sockets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io: {
  sockets: [{
    name: 'home',
    url: 'http://localhost:3000'
  }]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, to instantiate the nuxtSocket, it can be done in the &lt;code&gt;mounted()&lt;/code&gt; lifecycle hook. Usually, a channel is also specified to connect to a specific namespace on that server. If it is desired to opt-in to register the server's API, there are only a few things the developer has to do. First is first define a container for the API (&lt;code&gt;ioApi&lt;/code&gt;), and another for the API's data (&lt;code&gt;ioData&lt;/code&gt;). Then, to let the plugin know to register the API, he must specifying a &lt;code&gt;serverAPI&lt;/code&gt; as a JSON object (the JSON object contains registration options):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data() {
  return {
      ioApi: {}, // APIs in "KISS" format will get stored here
      ioData: {} // APIs data will live here, re-actively 
  }
},
mounted() {
  this.socket = this.$nuxtSocket({
    name: 'home', // use the "home" socket
    channel: '/dynamic', // use the "/dynamic" namespace
    serverAPI: {} // register the server's API, 
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! In it's most simple form, that's all that the developer would have to do to start using the API. Optional overrides will be discussed a little later. &lt;/p&gt;

&lt;p&gt;When the plugin first gets instantiated, the plugin will emit an event "getAPI" with an empty JSON object to the server. When the server responds with its API, first the plugin will determine the caching requirements: if a version mismatch is detected, the cache is updated. By default, the API cache stored in Vuex will use a label &lt;code&gt;"[socketName][channel]"&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;For all the methods that are defined in the API, the plugin will attach those methods to the &lt;code&gt;ioApi&lt;/code&gt; property you defined, and will initialize &lt;code&gt;ioData&lt;/code&gt; with the default values specified by each method's "msg" and "resp" schemas, respectively. This way, if even a very basic request were to be tested, it would work.&lt;/p&gt;

&lt;p&gt;For all the events that are defined in the API, the plugin will listen for those events, warning the developer about any duplicated listeners. As those events are received, the incoming data will be sent to &lt;code&gt;ioData&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  An example (server)
&lt;/h2&gt;

&lt;p&gt;So, suppose the server provides the following API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const api = {
  version: 1.02,
  evts: {
    itemRxd: {
      methods: ['getItems'],
      data: {
        progress: 0,
        item: {}
      }
    },
    msgRxd: {
      data: {
        date: new Date(),
        msg: ''
      }
    }
  },
  methods: {
    getItems: {
      resp: [Item]
    },
    getItem: {
      msg: {
        id: ''
      },
      resp: Item
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The very first time the client receives this, it has no cache and stores the API based on the socket's name and connected namespace "home/dynamic". Inspecting this API is extremely easy with Vue dev tools. The API will be in two places:&lt;/p&gt;

&lt;p&gt;1) It will be in Vuex:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KzqsOPPX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8wu5qrk0aftj8ha5ulq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KzqsOPPX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8wu5qrk0aftj8ha5ulq7.png" alt="Alt Text" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2) It will be in the component inspector: (this may be easier)&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--99rD8Otn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/l0fm6nipntp4heiz1uvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--99rD8Otn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/l0fm6nipntp4heiz1uvl.png" alt="Alt Text" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The "evts" and "methods" get saved to &lt;code&gt;this.ioApi&lt;/code&gt; and contain the schemas. The &lt;em&gt;actual&lt;/em&gt; methods get attached to &lt;code&gt;ioApi&lt;/code&gt;. As you can see, &lt;code&gt;ioApi.getItems&lt;/code&gt; and &lt;code&gt;ioApi.getItem&lt;/code&gt; are already defined functions.&lt;/p&gt;

&lt;p&gt;The other thing has happened is the initialization of &lt;code&gt;ioData&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z_JOH2xC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/d5zcusaodezzlkryklfg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z_JOH2xC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/d5zcusaodezzlkryklfg.png" alt="Alt Text" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means that your UI controls can now be data-bound to those &lt;code&gt;ioData&lt;/code&gt; values. Running any of the API methods will &lt;em&gt;also&lt;/em&gt; send the message contained in &lt;code&gt;ioData&lt;/code&gt; for that method, and send its response back to that &lt;code&gt;ioData&lt;/code&gt;'s container.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;ioApi.getItems()&lt;/code&gt; is already set to go (as indicated by &lt;code&gt;ioApi.ready == true&lt;/code&gt;, and simply running this method will &lt;em&gt;also&lt;/em&gt; send &lt;code&gt;ioData.getItems.msg&lt;/code&gt; with it. The response will get sent to &lt;code&gt;ioData.getItems.resp&lt;/code&gt;, in exactly the format that was initially set up. Also, since "itemRxd" was specified as an event that would be emitted by "getItems", &lt;code&gt;ioData&lt;/code&gt; already has a home for that event's data too. When "itemRxd" event is received, it will be sent to &lt;code&gt;ioData.getItems.itemRxd&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Looking at the "getItem" method, when &lt;code&gt;ioApi.getItem()&lt;/code&gt; is run, it will send &lt;code&gt;ioData.getItem.msg&lt;/code&gt; which was initialized as a JSON object, with "id" set to ''. The "id" can be bound to UI controls, so that if the id were changed, that "id" would get sent (that id is &lt;code&gt;ioData.getItem.msg.id&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Server API Registration Overrides
&lt;/h2&gt;

&lt;p&gt;The registration options at this time give you some control over what API you can request and how. You don't have to use the API label that the plugin creates for you, you can specify your own. Also, by default, the emitted event "getAPI" is used to get the API, but you can specify your own here too. Additionally, you can specify the message you want to send with that event, perhaps including the API version you want. &lt;/p&gt;

&lt;p&gt;Also, if for whatever reason, you would prefer a different name to use for "ioApi" or "ioData", it's done with "ioApiProp" and "ioDataProp", respectively. For example, you may instantiate multiple sockets on the same page, but would probably want to avoid using the same API object for different sockets.&lt;/p&gt;

&lt;p&gt;Lastly, if the server will be too noisy (i.e., emits too many events), you can specify the events to ignore with &lt;code&gt;apiIgnoreEvts&lt;/code&gt; (which today is an Array of strings; globbing would require overriding socket.io's internal methods, which I'd prefer to avoid).&lt;/p&gt;

&lt;p&gt;Here's what the overrides look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data() {
  return {
    serverApi: {},
    serverData: {},
  }
},
mounted() {
  this.socket = this.$nuxtSocket({
    name: 'home', // use the "home" socket
    channel: '/dynamic', // use the "/dynamic" namespace,
    ioApiProp: 'serverApi',
    ioDataProp: 'serverData',
    apiIgnoreEvts: ['noisyAlert'], // ignore this event
    serverAPI: { // register the server's API,
      label: 'myApi', // API label for this server will be used
      evt: 'getServerApi', // server-side method that will return server API
      msg: {
        version: 'latest' // server to return latest API version
      } 
    }
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you may be able request exactly the API version you want, and the API will go to exactly where you want. No need to look up API docs on some website, the API will just be in your dev tools. Plus, if you have &lt;code&gt;localStorage.debug = nuxt-socket-io&lt;/code&gt; the API will also get logged into the console log, for your convenience.&lt;/p&gt;

&lt;p&gt;The other override you have is choosing what message gets sent when you run an API method. I personally think it's easier to separate the methods from the data, but users may want to run the methods with arguments they pass to them. This certainly possible. So, if in the example above, if the user wanted to run &lt;code&gt;ioApi.getItem({ id: 'xyz' })&lt;/code&gt; or &lt;code&gt;ioApi.getItem({ someData: 222 })&lt;/code&gt;, both functions will emit the same "getItem" event with the supplied arguments as messages, but the former call would be expected to work, while the latter wouldn't, since it's not following the schema. Calling &lt;code&gt;ioApi.getItem()&lt;/code&gt; with empty arguments would always be expected to work because it will always use &lt;code&gt;ioData.getItems&lt;/code&gt; which was created directly from the server's API.&lt;/p&gt;

&lt;p&gt;An important note: &lt;em&gt;all&lt;/em&gt; server methods are expected to return something, at least an acknowledgement. The &lt;code&gt;socket.emit&lt;/code&gt; method that the plugin uses needs that response so it can resolve its promise.&lt;/p&gt;

&lt;h1&gt;
  
  
  Client API Registration
&lt;/h1&gt;

&lt;p&gt;Client API Registration is a bit easier, because the client already knows its API. It just has to communicate that to a server that requests it. This time, when the client API specifies "methods", this is letting the server know what events it (server) can emit; i.e., the client will &lt;em&gt;listen&lt;/em&gt; for those events. On the other hand, when the client API specifies "evts", those are events that it will emit. Some events may require acknowledgement others may not.&lt;/p&gt;

&lt;p&gt;You opt-in to register the client API by providing a &lt;code&gt;clientAPI&lt;/code&gt; JSON object when you instantiate the nuxtSocket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mounted() {
  this.socket = this.$nuxtSocket({
    name: 'home',
    channel: '/dynamic',
    clientAPI: {} // Here, you choose what methods to expose
  })
},
methods: { // Define client API methods here

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;clientAPI&lt;/code&gt; object represents the API in KISS API format. Unlike before, where the &lt;code&gt;serverAPI&lt;/code&gt; object represented the means for &lt;em&gt;retrieving&lt;/em&gt; the API, the &lt;code&gt;clientAPI&lt;/code&gt; here &lt;em&gt;is&lt;/em&gt; the API that the plugin will send to the server on request. A very important distinction. So, the "methods" in the clientAPI are events that the client will &lt;em&gt;listen&lt;/em&gt; for, and the "evts" are events that the client will emit. (It can sound confusing, but the &lt;em&gt;vue&lt;/em&gt; methods run when the &lt;em&gt;server&lt;/em&gt; emits the event of the same name, therefore client is listening for that event)&lt;/p&gt;

&lt;p&gt;After the page mounts, the plugin will listen for an event &lt;code&gt;getAPI&lt;/code&gt;, and upon receiving that event, will send back the API to the server that requested it. &lt;/p&gt;

&lt;h2&gt;
  
  
  An example (client)
&lt;/h2&gt;

&lt;p&gt;Consider the following Client API: (this describes the client's exposed methods and events at a page &lt;code&gt;ioApi.vue&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const ChatMsg = {
  date: new Date(),
  from: '',
  to: '',
  text: ''
}

const clientAPI = {
  label: 'ioApi_page',
  version: 1.31,
  evts: {
    warnings: {
      data: {
        lostSignal: false,
        battery: 0
      }
    }
  },
  methods: {
    receiveMsg: {
      msg: ChatMsg,
      resp: {
        status: ''
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;clientAPI&lt;/code&gt; is given a label, a version, evts and methods. The plugin expects that for each event name in "evts", there is at least a data property defined in the page. Here, it would expect &lt;code&gt;warnings = {}&lt;/code&gt; and the plugin would initialize the warnings data to what was defined in the API (&lt;code&gt;warnings.lostSignal = false&lt;/code&gt; and &lt;code&gt;warnings.battery = 0&lt;/code&gt;). For each event name, the plugin will create methods "[eventName]Emit", so that when the client wants to emit any of the events, it just calls that method (NOTE: on my roadmap, I may consider using property watchers that do the emitting automatically).&lt;/p&gt;

&lt;p&gt;Registering the clientAPI looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data() {
  return {
    /* Server API and Data (from before) */
    ioApi: {},
    ioData: {}

    /* Client Data */
    warnings: {} // warnings data
  }
},

mounted() {
  this.socket = this.$nuxtSocket({
    channel: '/dynamic',
    serverAPI: {},
    clientAPI
  })
},

methods: {
  someMethod() {
    // Not specified in API, so server should not know about this one.
  },

  receiveMsg(msg) { // Exposed method, server should be able to call it
    // Run this when server calls "receiveMsg(msg)"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when the server calls a method "receiveMsg(msg)" on it's end, the page on the client can expect the msg to be of type ChatMsg that it defined in its API. Here, it's up to the client's method to decide what to do with that msg. The plugin just passes it to the method.&lt;/p&gt;

&lt;p&gt;On the other hand, when the client wants to emit "warnings", it does so by calling a method the plugin created for it "warningsEmit". To send warnings, it's as simple as &lt;code&gt;this.warningsEmit()&lt;/code&gt; and the data contained in &lt;code&gt;this.warnings&lt;/code&gt; will be sent as the message. Again, if it is desired instead to send a different message, it would be done with arguments passed to the emit method: &lt;code&gt;this.warningsEmit({ battery: 98 })&lt;/code&gt;. The emit method can also accept an &lt;code&gt;ack&lt;/code&gt; boolean if the client requires acknowledgement on the event it emitted.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This article described the first implementation of dynamic API registration used by the nuxt-socket-io module and, at only 2 weeks old, may still have a lot of room for improvement. Expect pain points at first, but give it a fair chance and hopefully it will make it easier for your web apps to adapt to your server-side changes. &lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>nuxt</category>
      <category>api</category>
    </item>
    <item>
      <title>Re-Thinking Web APIs to be Dynamic and Run-Time Adaptable</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Thu, 02 Apr 2020 05:44:30 +0000</pubDate>
      <link>https://forem.com/richardeschloss/re-thinking-web-apis-to-be-dynamic-and-run-time-adaptable-31ek</link>
      <guid>https://forem.com/richardeschloss/re-thinking-web-apis-to-be-dynamic-and-run-time-adaptable-31ek</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;One of the most important aspects of all web applications is the Application Programming Interface (API), since it is the glue that allows the ends of a given communication channel to know exactly what to do. Because it is important for APIs to be robust, scalable and reliable, a lot of &lt;em&gt;manual&lt;/em&gt; effort goes into maintaining static APIs. In fact, &lt;a href="https://www.google.com/search?rlz=1C1CHBF_enUS857US857&amp;amp;ei=d0KFXq29AcnQ-gSH8ZuQBg&amp;amp;q=api+designer+jobs&amp;amp;oq=api+designer+jobs&amp;amp;gs_lcp=CgZwc3ktYWIQAzICCAA6BAgAEEc6BAgAEEM6BQgAEIMBOgkIABBDEEYQ-wE6BwgAEIMBEEM6CQgAEEMQRhD5AToFCAAQkQI6BggAEBYQHlC5oRBYr8QQYOPMEGgAcAJ4AIABuQGIAYoSkgEEMC4xN5gBAKABAaoBB2d3cy13aXo&amp;amp;sclient=psy-ab&amp;amp;ved=0ahUKEwjt1LKLzsjoAhVJqJ4KHYf4BmIQ4dUDCAs&amp;amp;uact=5"&gt;many&lt;/a&gt; tech companies set aside full-time roles &lt;em&gt;just&lt;/em&gt; for designing and maintaining the APIs. There is only one problem that we clearly missed all these years: APIs were never supposed to be &lt;em&gt;static&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;It can be argued that a given web app is only as good as the data it is able to access and display. While we are fortunate to live in a world full of data &lt;em&gt;sources&lt;/em&gt;, we only end up using the data sources we have access to (so, mathematically, probably works out to a very small percent of the world's data). Usually, each data source has its own unique API requirements, and this makes it a total drag whenever a new data source is to be used. Usually, it requires sufficient time allocation to read lengthy API docs, iterate over code that is only as robust as the API, and takes the developer away from other tasks on the backlog. This time and development cost can be incurred with every new incorporation of a data provider. &lt;/p&gt;

&lt;p&gt;Even if an app only has to concentrate on a single source, such as it's own backend, existing API models can still make iterating unnecessarily time consuming. And I would argue, a web app that relies on only one data source can quickly become a very boring app, since more often than not, its users will require constant engagement and different kinds of stimuli.&lt;/p&gt;

&lt;p&gt;Let's analyze what I perceive to be the most commonly used API model: (simplified greatly)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0jcb9XzD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/x7w6x7kfd4l6qf1paday.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0jcb9XzD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/x7w6x7kfd4l6qf1paday.png" alt="Alt Text" width="800" height="695"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this model, this is how I view it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;server&lt;/em&gt; owns the API, the client-side developer has to keep up to date with lengthy API docs&lt;/li&gt;
&lt;li&gt;The client makes &lt;em&gt;requests&lt;/em&gt;, the server &lt;em&gt;responds&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The client is expecting a single &lt;em&gt;response&lt;/em&gt;, so if there is something that happens in the time that the server performs the requested service, it will not be communicated back to the client. No notifications in this model, just a response.&lt;/li&gt;
&lt;li&gt;The communication is uni-directional; requests go one way, responses go the other. &lt;/li&gt;
&lt;li&gt;When the server's API changes, all clients are &lt;em&gt;blocked&lt;/em&gt; from communicating with the server until they update their request methods, &lt;em&gt;unless&lt;/em&gt; the server provides access to &lt;em&gt;previous&lt;/em&gt; versions. This is a terrible model because it's not reliable, or if it's reliable, it is costly because the server has to maintain &lt;em&gt;all&lt;/em&gt; versions of code just so older clients can use it. Newer versions of code &lt;em&gt;include bug fixes&lt;/em&gt; and other &lt;em&gt;enhancements&lt;/em&gt;, so it may be counter-productive for a client to insist on using old buggy code anyway.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may be much more beneficial to take a step back to really think about what our communication points on the web look like. This is illustrated in the next diagram. In the diagram, I still use the terms "server" and "client" because that's what everyone is still familiar with, but I would prefer the terms "IO node" for each point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lq0Yx83w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/qxdn2demgev8s2h98jh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lq0Yx83w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/qxdn2demgev8s2h98jh5.png" alt="Alt Text" width="795" height="1121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This picture zooms out of the previous model to think about many IO nodes on a given network. Here's how to view this model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each line represents bi-directional IO&lt;/li&gt;
&lt;li&gt;Each client and server can be thought of as IO &lt;em&gt;nodes&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;Each IO &lt;em&gt;node&lt;/em&gt; can emit or listen for events at any given time. Therefore, each node can have it's &lt;em&gt;own&lt;/em&gt; API it wishes to expose at any given point in time. Yes, the &lt;em&gt;client&lt;/em&gt; can have an API. &lt;/li&gt;
&lt;li&gt;Since those events are known at &lt;em&gt;run-time&lt;/em&gt;, each side can communicate the events it can emit and listen for; i.e., each node can communicate &lt;em&gt;its&lt;/em&gt; API. This means if a foreign IO node makes an appearance, indicated by "server 3", it can communicate &lt;em&gt;its API&lt;/em&gt; to any or all nodes, and those nodes will know how to communicate with that new node, all without having prior knowledge of its API.&lt;/li&gt;
&lt;li&gt;More importantly though, each node can communicate its &lt;em&gt;node type&lt;/em&gt;, so that if the two nodes are identical, they can be considered &lt;em&gt;peers&lt;/em&gt; and it can be deduced that peers must &lt;em&gt;already know&lt;/em&gt; each others APIs. &lt;/li&gt;
&lt;li&gt;This model is &lt;em&gt;only&lt;/em&gt; as robust as the API &lt;em&gt;format&lt;/em&gt; that all sides must have to agree on, but if the format is &lt;em&gt;simple&lt;/em&gt;, it can work!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A small digression
&lt;/h2&gt;

&lt;p&gt;I like to think of the client and server as being separated by great physical distances. Indeed this is already true as communication has to travel across long cables, bounce of satellites, etc. The response a client can get from a server should be expected to take some time. However, I like to take a bit more extreme view. I like to think of the client as someone traveling to a completely different planet, Mars or Pluto for example. That client will be even further away and for her to survive, she must constantly communicate back with IO servers back on Earth. In the years of her astronomic travels, more than likely both sides of this communication will morph in some way, and both sides will have to adapt to each others communication. Our beloved astronaut will not have the luxury of familiarizing herself with the latest API docs, she will simply have to make do with whatever the server sends her. What she &lt;em&gt;observes&lt;/em&gt; as "latest API" will from Earth's perspective already be a few versions old (physics), so maybe if the server can maintain only a few prior versions, she'll have a chance at surviving.&lt;/p&gt;

&lt;p&gt;This may be an extreme model, but one that can still apply to our web's constantly changing needs and APIs. And when the time comes to travel to distant planets, we'll be prepared.&lt;/p&gt;

&lt;h1&gt;
  
  
  The KISS Dynamic API Format
&lt;/h1&gt;

&lt;p&gt;If I can reference an old, but worthy acronym from the 60s, &lt;a href="https://en.wikipedia.org/wiki/KISS_principle"&gt;"KISS"&lt;/a&gt;, "The KISS principle states that most systems work best if they are kept simple rather than made complicated; therefore, simplicity should be a key goal in design, and unnecessary complexity should be avoided." -Wikipedia &lt;/p&gt;

&lt;p&gt;This is the design goal for what I devised as the "KISS Dynamic API Format". If the high-level format description cannot fit onto a Post-it® note, it will have failed the KISS principle. At a high-level, the KISS format looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q_X2ABYV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/5xojr5ehj423zn16z3ix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q_X2ABYV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/5xojr5ehj423zn16z3ix.png" alt="Alt Text" width="795" height="858"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the highest level, the format is simple: each IO node specifies it's label and version. If a given node communicating presents the same label and version as another node, it can be considered a &lt;em&gt;peer&lt;/em&gt;, at which point, that node would not need any extra information. Peers already know each others abilities. Nodes that are not peers, however, &lt;em&gt;would&lt;/em&gt; require more information: supported events and methods. (NOTE: the focus of this discussion is the IO model. A separate security model could possibly be implemented to help validate that IO nodes are who they say they are)&lt;/p&gt;

&lt;p&gt;If any of the nodes evolve, they must update their API, and communicate this new API with an updated version. Then, an IO node receiving this information can choose to update its API cache if it detects a version mismatch.&lt;/p&gt;

&lt;p&gt;If a label is not specified, the client will just have to rely on it's own alias to use for that API. Since the client &lt;em&gt;already knows&lt;/em&gt; the domain, port, and namespace it is communicating with, it can be a straightforward manner for it to create whatever aliases it wants (e.g., &lt;code&gt;apis['localhost:8080/chatRoom']&lt;/code&gt;). If a version is not specified, the client will always have to always assume a version mismatch and request the full API payload at the start of each new connection; i.e., the client won't be able to rely on or take advantage of an API cache. Therefore, while versioning is optional, it is highly recommended.&lt;/p&gt;

&lt;p&gt;Each node can have its own set of events and methods. "evts" means the node will &lt;em&gt;emit&lt;/em&gt; those events, while "methods" means the node will &lt;em&gt;listen&lt;/em&gt; for those events (and run its own methods of the same names, respectively).&lt;/p&gt;

&lt;h2&gt;
  
  
  KISS: The "evts" format
&lt;/h2&gt;

&lt;p&gt;Let's drill-down to the "evts" format, to see what it can look like: (again, must fit on a Post-it®)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OvDtPlOu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xe7d35c4gtm663qbn981.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OvDtPlOu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xe7d35c4gtm663qbn981.png" alt="Alt Text" width="795" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, the "evts" will take the following form: A JSON &lt;em&gt;object&lt;/em&gt; where the object properties are the event names, whose corresponding values are also optional JSON objects, but highly recommended. This makes it easy to write multiple events and keep things organized by event.&lt;/p&gt;

&lt;p&gt;Each event name points to a JSON object containing the following optional, but highly recommended, properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;methods&lt;/strong&gt;: an &lt;em&gt;array&lt;/em&gt; of strings, each string represents the method name emitting that event. This makes it easy for the receiver to organize event data by method name, in case different methods emit the same event. If omitted, the receiver would have to cache the emitted data in a more general, less organized, way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;data&lt;/strong&gt;: the schema that the client can expect to receive and use to validate incoming data. It is recommended that default values are used in the schema, since those values also indicate the data &lt;em&gt;type&lt;/em&gt; (in Javascript, &lt;code&gt;typeof (variable)&lt;/code&gt; tells us the type for primitives). This makes for simpler and more readable code, in my opinion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ack&lt;/strong&gt;: a boolean indicating whether or not the emitted event expects to be acknowledged. (This may or may not be needed, to be explained in a follow up article. It may be useful to know however, if code is blocking while waiting for an ack, when an ack will never get sent).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  KISS: An example using "evts" format
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FRWo-zNm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/9dvf86v2p6m5qre7i3ex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FRWo-zNm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/9dvf86v2p6m5qre7i3ex.png" alt="Alt Text" width="795" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, this API has label "mainServer" and is at version 1.02. It will emit the events "itemRxd" and "msgRxd". A client can expect that the methods emitting "itemRxd" will either be "getItems", "toBeAdded" or neither. It's up to the server to still specify the method that emitted that event so that the client can organize its data correctly. When the server emits "itemRxd", the client can expect the data JSON to contain "progress", which is specified as type Number (defaulted to 0), and the "item", which is specified as type Any (and defaulted to an empty object). In this way, both the &lt;em&gt;type&lt;/em&gt; and the &lt;em&gt;default value&lt;/em&gt; are represented in a simple and compact way. As time goes on, the server may wish to make "item" of type "Item", instead of "Any", to help the client validate each item (ex: Item schema = { name: '', description: '', unitCost: '' }). &lt;/p&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getItems(msg){
  socket.emit(
    'itemRxd', // event: 'itemRxd'
    { 
      method: 'getItems', // specify the method so the client can organize it.
      data: { 
        progress: 0.25 // getItems method is 25% complete, notify the client...
        item: { name: 'milk' } 
      }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other event is "msgRxd". This entry doesn't specify any method, only the schema for the data. The client can expect to receive the "date" and the "msg". Since no methods are specified, the client can expect the event to come from any or all methods on the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  KISS: The "methods" format
&lt;/h2&gt;

&lt;p&gt;While the "evts" container describes the &lt;em&gt;output&lt;/em&gt; of a given node, the "methods* describe the &lt;em&gt;input&lt;/em&gt; to that node, and what the corresponding response can be. This is what the format can look like: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_a5M7G5Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/t0aieqmnbjpl9pugimv4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_a5M7G5Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/t0aieqmnbjpl9pugimv4.png" alt="Alt Text" width="795" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The format is a JSON object, where the properties represent the supported method names. Each method name points to a corresponding JSON object, which describes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;msg&lt;/strong&gt;: the message schema that the receiving node expects (a "msg" JSON object)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resp&lt;/strong&gt;: the response schema the node expects to respond with, if any. If the response specifies a schema surrounded by square brackets, that specifies an Array of that schema. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One potential benefit of providing these schemas in real-time could be automatic UI creation; that is, certain types could help determine what UI elements are best suited for those types, especially if the types are primitives. For example, if a given msg schema specifies String and Number types, the String types could translate to &lt;code&gt;&amp;lt;input type="text" /&amp;gt;&lt;/code&gt; while Number types could translate to &lt;code&gt;&amp;lt;input type="number" /&amp;gt;&lt;/code&gt;. Entire form controls can probably be created on-the-fly in this manner. Likewise textual responses can probably be attached to &lt;code&gt;&amp;lt;div class="resp"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; elements. Styling could still largely be handled by CSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  KISS: An example using "methods" format
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jW5P6dYy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/n79km3by4s68ampnxasg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jW5P6dYy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/n79km3by4s68ampnxasg.png" alt="Alt Text" width="795" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, the API specifies two methods, "getItems" and "getItem". The "getItems" does not specify a "msg" schema, so "msg" can be anything (or nothing) because it will be ignored. The method will only return an Array of type "Item". The Item schema is defined as a JSON object of "id", "name", and "desc", all empty strings (type String). The "getItem" method, however, specifies a "msg" schema, a JSON object with a property "id" and format String (defaults to an empty string). When the client calls this method, the server expects that the client will provide an id of the correct type (String). It will respond with type Item.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Presented here was a lengthy, but hopefully not too confusing, discussion of how APIs can be made dynamic, so that they can adapt to changes made by both sides of a communication channel. This will most likely be a very new concept for many people, so my next article will describe the exact implementation of this, which will release with &lt;a href="https://www.npmjs.com/package/nuxt-socket-io"&gt;nuxt-socket-io&lt;/a&gt; v1.0.22. That article will try to explicitly highlight the benefits using concrete examples. Expect pain points at first, because it is a learning curve, but I am hopeful we'll both glad after climbing the curve (yes, we're climbing the curve together).&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>kiss</category>
      <category>dynamic</category>
      <category>webdev</category>
    </item>
    <item>
      <title>3 Minimally-Invasive Supercharged JS DEBUG Tools You Didn't Know You Had</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Sat, 18 Jan 2020 06:15:30 +0000</pubDate>
      <link>https://forem.com/richardeschloss/3-minimally-invasive-supercharged-js-debug-tools-you-didn-t-know-you-had-4n4k</link>
      <guid>https://forem.com/richardeschloss/3-minimally-invasive-supercharged-js-debug-tools-you-didn-t-know-you-had-4n4k</guid>
      <description>&lt;p&gt;Let me first describe the following behavior, and then let me know if this ever sounds like you. You have code that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const result = await getSomeData().catch(handleErr)
console.log('result', result)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, you have a large application, so you repeat that snippet at least a hundred times. Other parts of your code depend on &lt;code&gt;result&lt;/code&gt;, and when those other parts don't look right, you panic and frantically start adding more &lt;code&gt;console.log&lt;/code&gt; statements because "the code was supposed to be done yesterday":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log('result.id', result.id)
console.log('typeof result.id', typeof result.id)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully you don't practice the above behavior because then in all those places you have the debug statements, you'll have to remember to clean them out. Luckily, there are far easier ways to debug your code without requiring all the effort you think you might need.&lt;/p&gt;

&lt;p&gt;I'm going to try my best to keep this post &lt;em&gt;brief&lt;/em&gt; and organize this post from easy to easiest, because I know when you're frantically trying to debug something, you want the answer asap. &lt;/p&gt;

&lt;h2&gt;
  
  
  1) Spying on variables.
&lt;/h2&gt;

&lt;p&gt;First, if you must absolutely spy on a given variable, please quit doing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log('someVariable', someVariable)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, the above is easy to do, and I'm guilty of that bad habit, but the following is even easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log({ someVariable })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And yet, there is something even easier than the above. If you have Chrome dev tools, you can create something called "logPoints" (as &lt;a class="mentioned-user" href="https://dev.to/nickytonline"&gt;@nickytonline&lt;/a&gt; &lt;a href="https://dev.to/nickytonline/comment/kd2n"&gt;mentioned&lt;/a&gt;; see also &lt;a href="https://developers.google.com/web/updates/2019/01/devtools#logpoints" rel="noopener noreferrer"&gt;logpoints&lt;/a&gt;). They are exactly like breakpoints, but instead of breaking, messages get logged at those lines: (using the image he referenced)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevelopers.google.com%2Fweb%2Fupdates%2Fimages%2F2019%2F01%2Fadd-logpoint.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevelopers.google.com%2Fweb%2Fupdates%2Fimages%2F2019%2F01%2Fadd-logpoint.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specifically, here is something simple I did earlier today to help a new dev.to friend out. I just fired up the Chrome dev tools snippet editor, created the snippet, set the logPoint (which gets organized under "breakpoints") and ran the code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjrjg4a5dz39pjdjl347j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjrjg4a5dz39pjdjl347j.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resulted in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqph3kseqoe4bipy5em0c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqph3kseqoe4bipy5em0c.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I was able to eliminate the need to type "console.log" (11 characters); I became more efficient in my debugging efforts. Plus, I can easily disable (but keep) the logPoint simply by unchecking the checkbox. Since the logPoints are all organized in one place, this makes it easy to disable all, or enable all logging if the logPoint pins are in a myriad of places! But wait, we can do even better!&lt;/p&gt;

&lt;h2&gt;
  
  
  2) The &lt;code&gt;debug&lt;/code&gt; module
&lt;/h2&gt;

&lt;p&gt;TL;DR - YES, you can use it in the browser!&lt;br&gt;
TL;DR2 - YES, you can &lt;code&gt;import&lt;/code&gt; it!&lt;/p&gt;

&lt;p&gt;Check your "node_modules" folder for the "debug" folder! Considering the module is downloaded 56M+ times per week, there is a good chance you already have it somewhere on your machine! Even if you haven't listed it as a dependency, since so many projects use it, it is very likely that at least one of your dependencies shipped with it. For example, if/when you installed &lt;code&gt;socket.io-client&lt;/code&gt;, you &lt;em&gt;also&lt;/em&gt; installed the &lt;a href="https://www.npmjs.com/package/debug" rel="noopener noreferrer"&gt;debug module&lt;/a&gt; without realizing it! &lt;/p&gt;

&lt;p&gt;While I have high confidence that you may have used it to debug your server-side code like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const debug = require('debug')('server')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEBUG="server" node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you may not know is that the debug module can &lt;em&gt;also&lt;/em&gt; be used in the browser! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/l0NwHXQy3kUSfFF60/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l0NwHXQy3kUSfFF60/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not only can you use it in the browser, you can &lt;em&gt;import&lt;/em&gt; the debug module using the &lt;code&gt;import&lt;/code&gt; syntax you've been familiar with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;myComponent.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Debug from 'debug'
const debug = Debug('myComponent')

...
const result = await getSomeData().catch(handleError)
debug({ result })
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to actually see the debug statements in the browser's console log, you don't set any environment variables but instead just set the &lt;em&gt;debug&lt;/em&gt; variable in &lt;code&gt;localStorage&lt;/code&gt;. But...whatever you do, avoid setting that variable in your own code! It is far safer to set it in your Chrome dev tools! This way, your code doesn't accidentally ship with debug logging enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa8d5i5kchcq08a8za41e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa8d5i5kchcq08a8za41e.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now, when you have that variable set, all the debug statements will log to the console for &lt;code&gt;myComponent.js&lt;/code&gt;. If you want to debug multiple files, each file can get it's own or shared debug string, in which case the &lt;code&gt;localStorage.debug&lt;/code&gt; variable just needs to be a comma-separated string or wildcard ('*'):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localStorage.debug = 'myComponent, otherComponent' // logs for both components

localStorage.debug = '*' // all debug log statements in browser will log to console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/9V1F9o1pBjsxFzHzBr/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/9V1F9o1pBjsxFzHzBr/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many modules that depend on the debug module &lt;em&gt;already have&lt;/em&gt; debug strings that they used to help themselves (and you) debug what is going on with &lt;em&gt;their&lt;/em&gt; module. Two such modules are &lt;code&gt;socket.io-client&lt;/code&gt; and &lt;code&gt;nuxt-socket-io&lt;/code&gt;. This means that when you want to debug the IO going into and out of each part of your component, you don't need to write a single &lt;code&gt;console.log&lt;/code&gt; statement! You simply set the &lt;code&gt;localStorage.debug&lt;/code&gt; variable to the correct string(s):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localStorage.debug = 'socket.io-client:socket' // Monitor socket.io-client

localStorage.debug ='nuxt-socket-io, socket.io-client:socket' // debug even more...


// Then, when it is desired to mute the logs...simply make debug undefined:
localStorage.debugX ='nuxt-socket-io, socket.io-client:socket' // debug nothing just by putting an X there (or whatever you like!)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, when I have &lt;code&gt;localStorage.debug&lt;/code&gt; set to this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcqe0vj97d3t5e1kydmpf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcqe0vj97d3t5e1kydmpf.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I get logs that look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socket.io-client:socket emitting packet with ack id 1 +11s
socket.io-client:socket emitting event ["chatMessage","Hi, this is a chat message from IO server!"] +507ms 
nuxt-socket-io Vuex listener received data +11s {evt: "chatMessage", resp: "Hi, this is a chat message from IO server!"}
socket.io-client:socket emitting event ["chatMessage","Hi, this is another chat message from IO server!"] +504ms
nuxt-socket-io Vuex listener received data +507ms {evt: "chatMessage", resp: "Hi, this is another chat message from IO server!"}
socket.io-client:socket calling ack 1 with ["It worked! Received msg: {\"id\":\"abc123\"}"] +41ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, when I wrote the debug statements, I only had to write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;debug('some message', { data })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But...the log entries consist of other useful pieces of information that I didn't have to think about coding, such as: the file and line producing that log entry, and the time between debug statements. If the logs were to become lengthy, Chrome dev tools makes it simple to save the console logs with a right-click and menu selection.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger" rel="noopener noreferrer"&gt;"debugger"&lt;/a&gt; keyword.
&lt;/h2&gt;

&lt;p&gt;Oftentimes, the code that runs in the browser is a gigantic uglified version of your source code. Trying to insert a needle of a breakpoint into a very messy haystack can be time-consuming. Fortunately, the "debugger" keyword is built into the language and can be used to break on a point of interest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function myCodeAintWorkin(arrrrgggh) {
  let thisThing;
  debugger; // &amp;lt;-- runtime will break at this point! (even if this line is buried in the uglified code at line 1112442)
  // Some buggy code here
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, going back to the original &lt;code&gt;CarsArray&lt;/code&gt; snippet, I could have also debugged the &lt;code&gt;filtered&lt;/code&gt; variable like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffzk2g7qqjkatgj5szldp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffzk2g7qqjkatgj5szldp.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, while, I did not have to type "console.log" (11 chars), I did have to type "debugger" (8 chars), but the additional benefit I got was that just by looking a few inches to the right, I was able to see the &lt;em&gt;local scope&lt;/em&gt; instantly and fiddle with the properties as I desired. All this &lt;em&gt;without&lt;/em&gt; having to write several more &lt;code&gt;console.log&lt;/code&gt; statements:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzm7leelxfyspa4nttuc8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fzm7leelxfyspa4nttuc8.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this above image, I was able to try out a second "filtered2" statement by toggling the "age" property of the Dodge to less than 10 years. In case I doubted my first filtered statement, I could try changing the properties and assert that the new list of cars older than 10 years consists of one less car.&lt;/p&gt;

&lt;p&gt;As cool as the "debugger" keyword is, it may be a very good idea to remove the line when your code is ready to be merged in to your team's codebase, because your team will most likely not want &lt;em&gt;their&lt;/em&gt; code to break on &lt;em&gt;your&lt;/em&gt; debug statements.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Whether or not the term "tool" applies to all three debugging approaches mentioned above I think can be up to debate. The first method takes advantage of JS object structuring, which you use as a tool to spy on variables (&lt;code&gt;console.log({ someVar }&lt;/code&gt;). The second approach uses one of the most popular debugging utilities in the JS ecosystem, combined with Chrome Dev Tools to help you debug in the browser. Lastly, the third method is the "debugger" keyword, which along with Chrome Dev Tools, you use like a tool to figure out application state at a given line in code. &lt;/p&gt;

&lt;p&gt;I tried my best to order the tools by ease-of-use. How "easy" a certain debugging approach may be is certainly subjective. I personally find the second approach to be the easiest, but many more may find the third to be easiest. Either way, even if you are an experienced developer, I hope you found this post helpful. &lt;/p&gt;

</description>
      <category>io</category>
      <category>debug</category>
      <category>javascript</category>
      <category>easyas123</category>
    </item>
    <item>
      <title>Nuxt Socket.IO: Connection Status and Error Handling Made Easy</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Tue, 07 Jan 2020 04:19:35 +0000</pubDate>
      <link>https://forem.com/richardeschloss/nuxt-socket-io-connection-status-and-error-handling-made-easy-4p2k</link>
      <guid>https://forem.com/richardeschloss/nuxt-socket-io-connection-status-and-error-handling-made-easy-4p2k</guid>
      <description>&lt;p&gt;TL;DR - If you've been in web development for the past few years, you may have heard the debate on error handling. "Use try / catch!", "No, use async / await / .catch!", "No, use promises / .catch!". Presented here are two new features that help developers clearly understand the connection status to a given IO socket and handle errors in a much cleaner, reactive way. With the plugin absorbing this responsibility, and now with developers having a completely new alternative and perspective on the issue at hand, hopefully the whole debate on error handling gets muted due to obsolescence of the underlying premise.&lt;/p&gt;

&lt;p&gt;Disclaimer: I am the author &lt;a href="https://npmjs.com/package/nuxt-socket-io"&gt;nuxt-socket-io&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Unless you are Mr. Robot, who gets his code to work the first shot, you will most likely run into errors when your code attempts to request data from either your backend or some other service. Most likely, your code looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try { 
  const resp = await Svc.getData({ userId: 'abc123' })
  if (resp !== undefined) { // Note: Please don't do this. 
    // If it's undefined, it's an error if you were expecting a response.
    /* handle response */
  }
} catch (err) {
  /* handle error */ // this placeholder comment stays here forever
  throw new Error(err) // Note: Please don't do this! 
  // ^^ Don't catch an error just to throw it!)
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both blocks of code seem pretty simple and somewhat elegant, but the issue can quickly become a mess when you have many different kinds of requests to send. Your code will become littered with many try/catch blocks before you realize it. Considering that VueJS gives us reactive properties, and lets us create computed properties that change whenever other properties change, I think we can do better!&lt;/p&gt;

&lt;p&gt;Here's my perspective. When I call some method to get data, these are my expectations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// I want my request to be simple: (i.e., just make the request)
Svc.getData(...) // I just want to call this and have the response get sent directly to a property "resp".

// Success handling: (if all was good, handle response)
function handleResp(resp) { // If I want to post-process resp, I call this
  /* handle resp */
  // The response is valid here, if not...
  // I have no business calling this function
}

// Error handling: (if errors occurred, collect them and don't set property "resp")
emitErrors: { // &amp;lt;-- send any errors directly to this property
  getData: [{...}], // &amp;lt;-- send specific getData errors here
  // it's useful to include hints and timestamps
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, I can separate my concerns and keep my code completely organized. If &lt;code&gt;emitErrors&lt;/code&gt; becomes truthy, I can easily style different parts of the page or component based on that (using &lt;em&gt;computed properties&lt;/em&gt;). Plus, if I can eliminate the need for &lt;em&gt;validating&lt;/em&gt; the response inside of a &lt;code&gt;handleResp&lt;/code&gt; method, I &lt;em&gt;also&lt;/em&gt; eliminated the need to have a &lt;em&gt;test case&lt;/em&gt; for that. The time savings can seriously add up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connection Status
&lt;/h2&gt;

&lt;p&gt;Many IO errors can be traced back to the actual connection to the service. Is the client even connected? This is the most fundamental question to ask, but easy to overlook. Fortunately, the socket.io-client exposes several events that the nuxt-socket-io plugin can listen for to determine the status &lt;em&gt;if&lt;/em&gt; the user opts-in to listen (explained below). The following events are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const clientEvts = [
  'connect_error', 
  'connect_timeout',
  'reconnect',
  'reconnect_attempt',
  'reconnecting',
  'reconnect_error',
  'reconnect_failed',
  'ping',
  'pong'
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it is desired to check the status, the user simply opts-in by defining the property &lt;code&gt;socketStatus&lt;/code&gt; on the same component that instantiates &lt;code&gt;this.$nuxtSocket&lt;/code&gt;. The &lt;em&gt;plugin&lt;/em&gt; will then automatically set that status (it will use the camel-cased versions of the event names as prop names, since that's a common convention in Javascript). If it is desired to use a prop name other than &lt;code&gt;socketStatus&lt;/code&gt;, the ioOpts property &lt;code&gt;statusProp&lt;/code&gt; just needs to be set.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data() {
  return {
    socketStatus: {}, // simply define this, and it will be populated with the status
    badStatus: {} // Status will be populated here if "statusProp == 'badStatus'"
  }
},
mounted() {
  this.goodSocket = this.$nuxtSocket({
    name: 'goodSocket',
    channel: '/index',
    reconnection: false
  })

  this.badSocket = this.$nuxtSocket({
    name: 'badSocket',
    channel: '/index',
    reconnection: true,
    statusProp: 'badStatus' // This will cause 'badStatus' prop to be populated
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a convenience to you, a SocketStatus.vue component is now also packaged with nuxt-socket-io, which will help visualize the status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;socket-status :status="socketStatus"&amp;gt;&amp;lt;/socket-status&amp;gt;
&amp;lt;socket-status :status="badStatus"&amp;gt;&amp;lt;/socket-status&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will produce the following dynamic tables:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1vRSa75m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/c79o9eus84jwykxq5dkl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1vRSa75m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/c79o9eus84jwykxq5dkl.png" alt="Alt Text" width="651" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, with the socketStatus props being reactive, it makes it easy to show or hide parts of a given page based on the connection status.&lt;/p&gt;
&lt;h2&gt;
  
  
  Error Handling
&lt;/h2&gt;

&lt;p&gt;Even when a connection is solid, it is still possible for IO errors to occur. Two main categories of errors can be thought of as: 1) timeout- and 2) non-timeout related. The plugin allows the user to take advantage of new built-in error handling features.&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;Handling timeout errors&lt;/strong&gt;. It's possible for a timeout error to occur if the client is connected but makes an unsupported request (the request will just never get handled). The user opts-in to let the plugin handle timeout errors by specifying an &lt;code&gt;emitTimeout&lt;/code&gt; (ms) in the IO options when instantiating &lt;code&gt;this.$nuxtSocket&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.socket = this.$nuxtSocket({ channel: '/examples', emitTimeout: 1000 }) // 1000 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, if an "emitTimeout" occurs, there are two possible outcomes. One is, the plugin's method will reject with an "emitTimeout" error, and it will be up to the user to catch the error downstream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.someEmitMethod() 
.catch((err) =&amp;gt; { // If method times out, catch the err
  /* Handle err */
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above allows the user to write code in a manner that already feels familiar, however, I think there is an even easier way to deal with the error.&lt;/p&gt;

&lt;p&gt;The plugin can provide a completely different way of handling an error, depending on whether the user allows it to or not. If the user defines a property "emitErrors" on the component and the server responds with an error attached (i.e., an object with the defined property "emitError"), the plugin won't throw an error, but will instead set the property on the component (&lt;code&gt;this.emitErrors&lt;/code&gt;) and organize &lt;code&gt;this.emitErrors&lt;/code&gt; by the faulty emit event. This may result in much cleaner code, and may make it easy to work with the component's computed properties that will change when "emitErrors" property changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data() {
  emitErrors: {} // Emit errors will get collected here, if resp.emitError is defined
}
...
this.someEmitMethod() // Now, when this times out, emitErrors will get updated (i.e., an error won't be thrown)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important NOTE: in order for &lt;code&gt;this.emitErrors&lt;/code&gt; to get updated, the server must send it's error response back as an object, and define a property "emitError". It is recommended for the backend to also attach error details to the response to aid with troubleshooting.&lt;/p&gt;

&lt;p&gt;2) &lt;strong&gt;Handling non-timeout errors&lt;/strong&gt;, such as bad requests, or anything specific to your application's backend. Again, like before, if &lt;code&gt;this.emitErrors&lt;/code&gt; is defined in the component, &lt;em&gt;and&lt;/em&gt; the response is an object with a defined property "emitError", the property &lt;code&gt;this.emitErrors&lt;/code&gt; will get set on the component, otherwise, an "emitError" will get thrown. If it is desired to use a different name for the emitErrors prop, it is done so by specifying "emitErrorsProp" in the ioOptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data() {
  myEmitErrors: {} // Emit errors will get collected here now
}

mounted() {
  this.socket = this.$nuxtSocket({ emitErrorsProp: 'myEmitErrors' })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Half-filled Promise
&lt;/h2&gt;

&lt;p&gt;At the beginning of the article one of my first code snippets mentioned how I would want an empty to response to be considered as an error. This is still something I would like to consider, however, at the time of this writing, the plugin does not treat it as such. It only treats a defined &lt;code&gt;resp.emitError&lt;/code&gt; as a non-timeout error. I think it is safer for now for me to assume that not all users would want me to handle their empty responses for them, which is why I require them to opt-in in the manner described above. I would love it if enough people would want automated empty-response handling, but I first want to see how far people get with the code as-is before building more into it. Baby steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article reviewed a completely different, and hopefully much simpler, way to deal with IO connection status and errors. When life seems to present us with only a few ways to solve a problem (try/catch vs. promise/catch), I like to think of yet another way to solve the problem with less effort, whenever possible. The plugin now includes that other way and I hope you find it helpful!&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>javascript</category>
      <category>vue</category>
      <category>easy</category>
    </item>
    <item>
      <title>Nuxt Socket.IO: How to Create a Stealth-mode Chat Application in Under 10 minutes</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Sun, 29 Dec 2019 06:22:53 +0000</pubDate>
      <link>https://forem.com/richardeschloss/nuxt-socket-io-how-to-create-a-stealth-mode-chat-application-in-under-10-minutes-1m2g</link>
      <guid>https://forem.com/richardeschloss/nuxt-socket-io-how-to-create-a-stealth-mode-chat-application-in-under-10-minutes-1m2g</guid>
      <description>&lt;p&gt;TL;DR - In the last post in this series, a new namespace configuration feature was presented. A special syntax was presented with the feature, and this article shows how to configure the module to create a simple and anonymous chat application in less than 10 minutes. The goal of this article is to illustrate how much can be done in the &lt;code&gt;nuxt.config&lt;/code&gt;, and how much less code would be needed at the page- and component- level to accomplish the task.&lt;/p&gt;

&lt;p&gt;Disclaimer: I am the author of the &lt;a href="https://www.npmjs.com/package/nuxt-socket-io" rel="noopener noreferrer"&gt;nuxt-socket-io&lt;/a&gt; module.&lt;/p&gt;




&lt;h2&gt;
  
  
  Suggested reading:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/javascript-in-plain-english/introduction-to-nuxt-socket-io-b78c5322d389" rel="noopener noreferrer"&gt;Introduction to Nuxt Socket.IO&lt;/a&gt; - This describes the Nuxt Socket.IO and basic setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/richardeschloss/nuxt-socket-io-how-namespaces-config-may-make-your-life-insanely-easier-23ml"&gt;Namespace configuration explained&lt;/a&gt; - Describes the feature and syntax.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The above items are good to read, however, I will try to write this article to make the example easy to follow, regardless of previous knowledge. Familiarity with Nuxt and VueJS ecosystem should be enough to help you get through the example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic setup:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone or fork my git repo: &lt;a href="https://github.com/richardeschloss/nuxt-socket-io" rel="noopener noreferrer"&gt;https://github.com/richardeschloss/nuxt-socket-io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install the dependencies: &lt;code&gt;npm i&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run the server with &lt;code&gt;npm run dev:server&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open at least two browser tabs and navigate to the chat rooms page at: &lt;a href="https://localhost:3000/rooms" rel="noopener noreferrer"&gt;https://localhost:3000/rooms&lt;/a&gt; and have fun! Simple chat messages should be sent back and forth between the clients. The rest of the article simply explains what is going on and how this was accomplished.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configuring the namespaces:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;First let's take a look at the namespaces config inside &lt;code&gt;nuxt.config.js&lt;/code&gt;:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4zmvc07c5mmtlilypznj.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First we have a namespace for &lt;code&gt;/rooms&lt;/code&gt;. This namespace will only care about any communication at the "rooms" level. Therefore, there is an emitter which will emit an event "getRooms" and the server will respond. When it does, we set the corresponding page's data &lt;code&gt;this.rooms&lt;/code&gt; to that response. If we wanted to, we could also set up an extra emitter, say "crudRoom + roomInfo --&amp;gt; rooms" which would send an event "crudRoom" to &lt;strong&gt;cr&lt;/strong&gt;eate/&lt;strong&gt;u&lt;/strong&gt;pdate/&lt;strong&gt;d&lt;/strong&gt;elete the room specified in the &lt;code&gt;this.roomInfo&lt;/code&gt; message. The response back would set &lt;code&gt;this.rooms&lt;/code&gt; to the new response. If race conditions were a concern, we could simply change the name of the destination.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next we, have a namespace for &lt;code&gt;/room&lt;/code&gt;. There are two emitters. One emitter will send the event "joinRoom" with the message "joinMsg". On the page, &lt;code&gt;this.joinMsg&lt;/code&gt; will contain information about the user joining the room. The server will handle the joining of sockets to a unique namespace, as this is how the socket.io server works (&lt;code&gt;socket.join&lt;/code&gt; is done server-side). After successful join, the server responds and &lt;code&gt;this.roomInfo&lt;/code&gt; will get set with that data. The second emitter is there to do the opposite of joining: "leaveRoom" and send the message "leaveMsg", which would contain the user leaving the room. In order to alert &lt;em&gt;other&lt;/em&gt; clients of the join and leave events, listeners have to be set up on the clients. Here we simply specify listeners for "joinedRoom" and "leftRoom" events, and also specifying a post hook "updateUsers" to run after receiving the new information. Like in step 1, it's possible that we may want to register even more emitters, for perhaps editing the room info, or notifying existing users about other room-wide events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lastly, we have a namespace for &lt;code&gt;/channel&lt;/code&gt;. What is channel? Well, it's really just like "/room" but a room inside of a room. The only difference here is we treat the channel as the namespace to allow for message sending and receiving. Therefore, there is an emitter "sendMsg" which will send the "sendMsg" event with the user's message &lt;code&gt;this.userMsg&lt;/code&gt;. The server will echo the user's message back (to acknowledge receipt), and after the user receive's the message, the page data &lt;code&gt;this.msgRxd&lt;/code&gt; will get set and the post hook &lt;code&gt;appendChats&lt;/code&gt; will append the chat to that user's copy of the chat history. For &lt;em&gt;others&lt;/em&gt; in the room to see the message, they need to listen for the "chatMessage" event and do exactly the same thing &lt;code&gt;appendChats&lt;/code&gt; after receiving the message. Note: in my example, I don't actually use &lt;code&gt;this.msgRxd&lt;/code&gt;, but I am still choosing to have it there in case I plan to use it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Page structure
&lt;/h2&gt;

&lt;p&gt;Here is how the pages are structured in the pages folder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5pa6p957kisp6kithni3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5pa6p957kisp6kithni3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're new to Nuxt, here's the 30 second crash course on automatic route generation (and why 24.5k+ people love Nuxt): Nuxt will automatically create nested routes based on how folders and files are structured in the "pages" folder. If the pages folder contains &lt;em&gt;both&lt;/em&gt; a vue file and folder of the same name, then the files in the folder will be treated as children of the parent vue file. The parent vue file just needs to remember to include a &lt;code&gt;&amp;lt;nuxt-child&amp;gt;&amp;lt;/nuxt-child&amp;gt;&lt;/code&gt; in the template so the child pages get placed where the &lt;code&gt;&amp;lt;nuxt-child&amp;gt;&amp;lt;/nuxt-child&amp;gt;&lt;/code&gt; element is. Furthermore, the underscore has a special reserved meaning in NuxtJS. It's used to indicate a parameter-based route. This is exactly what we want. When a child page wants to get the value of that route parameter, it does it by looking in &lt;code&gt;$route.params[childPage]&lt;/code&gt;. Therefore, "_room.vue" would look at &lt;code&gt;$route.params.room&lt;/code&gt; and "_channel.vue" would look at &lt;code&gt;$route.params.channel&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Rooms Page
&lt;/h2&gt;

&lt;p&gt;Here are the key parts of the rooms page, which will only care about the "rooms" namespace:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2sl7szpiddb2njq7361j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2sl7szpiddb2njq7361j.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main requirements are instantiating the client, specifying the namespace for the client to use, and defining properties that will expect to receive data. In this case it is &lt;code&gt;this.rooms&lt;/code&gt;. What you'll notice is there is &lt;em&gt;no need&lt;/em&gt; to define the &lt;code&gt;getRooms&lt;/code&gt; method. In fact, doing so may break the plugin! You &lt;em&gt;already&lt;/em&gt; specified it once in the nuxt config, and that's all to be done. The plugin will take care of the rest!&lt;/p&gt;

&lt;h2&gt;
  
  
  Room Page
&lt;/h2&gt;

&lt;p&gt;Here are the key parts of the room page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F3393u3lmwhhvs7ppypsz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F3393u3lmwhhvs7ppypsz.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, like before, simply define the props that were entered in &lt;code&gt;nuxt.config&lt;/code&gt; and when it is desired to use the emitter methods, just &lt;em&gt;use them&lt;/em&gt;. The post hook "updateUsers" is the only method we need to define. &lt;/p&gt;

&lt;p&gt;Now, I think I know what most readers will think. If the plugin can create the emitter methods, can't it also just automatically create the props to save the user one more lengthy step? Well, the answer is yes with a major caveat. For the plugin to absorb that responsibility, it would have to enforce and assume a datatype for every property, most likely an object. While it is my personal style to encapsulate all IO messages in &lt;em&gt;objects&lt;/em&gt;, adhering to the format &lt;code&gt;{ err: ..., data: ..., meta: ...}&lt;/code&gt; all users may not want to be forced to do that. And, since I can't possibly know the requirements of all projects, I could end up alienating a large user base by enforcing that. Some users may want to send simpler data types (numbers, strings) or objects of a different format. Plus, this way, the developers also have control over the initial values for their properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Channel Page
&lt;/h2&gt;

&lt;p&gt;Lastly, here are the key parts of the channel page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8kppsvgzugffqvjs51ef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8kppsvgzugffqvjs51ef.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8k48yctuk948ekpic3ih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8k48yctuk948ekpic3ih.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This looks almost exactly the same as the room page! In fact, maybe with more effort, I could have reused even more code between the two pages! The only real functional difference is that it is on the channel page where we allow messages to be sent and received. &lt;/p&gt;

&lt;p&gt;The user's &lt;code&gt;inputMsg&lt;/code&gt; is encapsulated in the page's &lt;code&gt;this.userMsg&lt;/code&gt; object, which will also contain the user's name when the "sendMsg" event is sent. This is primarily for illustrative purposes, but it should be noted, that one interesting thing about &lt;em&gt;socket.io&lt;/em&gt; is that each socket gets a unique ID (both the client and server will be aware of the &lt;code&gt;socket.id&lt;/code&gt; at initial connection). It may be more appropriate to send the socket.id instead of the user name with each event. The server could maintain an id-to-user map in this case. &lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus (did you notice the extra goodies?)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;On the server-side, as a tribute to the way Nuxt does things with routes, my IO module on the back-end automatically registers namespaces based on the folder structure. Files in the "namespaces" folder will automatically accept connections to namespace matching &lt;code&gt;/[filename]&lt;/code&gt;. This should make it easier to write the server-side logic. Simply make the methods mirror the front-end methods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Page-level tests to make testing quicker than manual testing in the browser. If you haven't experienced &lt;code&gt;vue-test-utils&lt;/code&gt;, you may learn to love it. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS-grid on the front end. So, if you were hoping to learn it, you can learn from these examples (just scroll down to the "style" section where it's used). Moreover, both the room.vue and channel.vue pages use it (so you can nest a CSS-grid inside another CSS-grid; originally, I thought this would break things, but apparently not)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your username is not a real name, it's a pseudo random number generated based on the time you connected to the rooms page. At any time you want to change your username, you simply click the refresh page and you get a new identity. So somewhat of a "stealth" mode (but not real security, don't rely on this entirely).  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Things to Note
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There is still plenty room for improvement in the plugin and the example. Planned for the near future may be better error handling. Currently, the developer will have to handle errors in the post-level hooks, but I have some ideas for improved solutions in future versions. The socket.io-client under the hood also provides error messages, such as "failure to connect" errors, which can probably be handled cleanly. Stay tuned.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The example could include support for CRUD operations so that users can create, edit or delete rooms and channels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Certain parts of the page can probably go into components, such as each chat message in the chat history. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Ok, there you have it. In my headline, I promise "10 minutes" and, considering this was a 7 minute read, you now have 3 minutes to get it working to not make a liar out of me! :). I hope you have fun with it. No need to pay some corporation a ton of money for a chat application...you just launched one for free! And yes, I won't track your chats! Happy chatting!&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>javascript</category>
      <category>socketio</category>
    </item>
    <item>
      <title>Nuxt-Socket.IO: How Namespaces Config May Make Your Life Insanely Easier</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Sat, 28 Dec 2019 05:33:57 +0000</pubDate>
      <link>https://forem.com/richardeschloss/nuxt-socket-io-how-namespaces-config-may-make-your-life-insanely-easier-23ml</link>
      <guid>https://forem.com/richardeschloss/nuxt-socket-io-how-namespaces-config-may-make-your-life-insanely-easier-23ml</guid>
      <description>&lt;p&gt;TL; DR -- This Christmas present has arrived a little late, but I think users of the &lt;a href="https://www.npmjs.com/package/nuxt-socket-io"&gt;nuxt-socket-io&lt;/a&gt; will like it, once it's fully understood. Now, it is possible to configure socket.IO emitters, listeners, and "emitbacks" directly in &lt;code&gt;nuxt.config&lt;/code&gt; for specified &lt;em&gt;namespaces&lt;/em&gt;. This article describes how to take advantage of the new feature.&lt;/p&gt;

&lt;p&gt;Disclaimer: I am the author of the nuxt-socket-io module. I present here a new kind of syntax which may take some getting used to, but I think it's a syntax that makes sense. Approach it with an open mind. &lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://medium.com/javascript-in-plain-english/introduction-to-nuxt-socket-io-b78c5322d389"&gt;Introduction to Nuxt Socket.IO&lt;/a&gt; - This describes the Nuxt Socket.IO and basic setup.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Socket.IO is the real-time engine for the web, and the Nuxt-Socket.IO module is the module that makes it clean and straightforward to use inside your Nuxt application. A lot of times, it is desired to instantiate socket.IO client inside of components, and then restrict the scope of communication to only what those components should and would care about. &lt;/p&gt;

&lt;p&gt;For example, a chat room component might only want to talk to a chat room service, and a room's channel might only want to talk to that channel's service. The messages that get sent in a specific channel shouldn't leak out to the rest of the room. Whether or not we refer to them as "channels" or "rooms", the word "namespaces" seems to be most fitting for each case. Plus, whereas "rooms" and "channels" confine our thinking to that of "just a chat application", the term "namespaces", on the other hand, is universal and allows to think of scoped communication for all of our web applications. &lt;/p&gt;

&lt;p&gt;In addition to scoping a component's IO to that of a given namespace, it is often desirable to also signal a disconnect (i.e., close the socket) when the component is destroyed. While it is good practice for developers to do their own cleanup steps, such practice can either be cumbersome or easy to forget for every component in a given application.&lt;/p&gt;

&lt;p&gt;Therefore, with the aforementioned in mind, the nuxt-socket-io plugin and namespace config feature had the following goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The plugin had to allow namespaces to be configured in &lt;code&gt;nuxt.config&lt;/code&gt; for each socket.&lt;/li&gt;
&lt;li&gt;The plugin had to support the configuration of emitters, listeners, and "emitbacks" at the page- and component-level. &lt;/li&gt;
&lt;li&gt;The configuration had to be as straightforward as that for vuex options (listeners and emitbacks), for users who already configured the module.&lt;/li&gt;
&lt;li&gt;The new feature had to support a new and, arguably, a more intuitive arrow (&lt;code&gt;--&amp;gt;&lt;/code&gt;) syntax. This makes IO config easier to version control, and share with stakeholders (non-devs), if needed.&lt;/li&gt;
&lt;li&gt;The configuration had to allow support for hooks to be run before and after the specified IO events. &lt;/li&gt;
&lt;li&gt;The plugin had to automatically disconnect the socket before the component is destroyed, by default (overwriting this is possible with the &lt;code&gt;teardown: false&lt;/code&gt; option passed to &lt;code&gt;this.$nuxtSocket&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The plugin had to make life easier for application developers by encouraging them to write less, but more consistent code.&lt;/li&gt;
&lt;li&gt;The plugin still had to expose the socket.io client instance in case the developer needed to access the client API methods directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today, it is now possible to configure namespaces in &lt;code&gt;nuxt.config&lt;/code&gt;. Each socket set can have its own configuration of namespaces and each namespace can now have emitters, listeners, and emitbacks. The configuration supports an arrow syntax in each entry to help describe the flow (with pre/post hook designation support too). &lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Namespaces
&lt;/h2&gt;

&lt;p&gt;This section describes how to configure emitters, listeners and emitbacks for each namespace. The general syntax is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;preHook] body [postHook&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes the body includes a "+", "&amp;lt;--" or a "--&amp;gt;". While the use and placement of the characters "]", "[", "+", "&amp;lt;--", and "--&amp;gt;" is strict, the &lt;em&gt;names&lt;/em&gt; you use for hooks, events, and props are entirely up to you.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;specific&lt;/em&gt; syntax is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Emitters&lt;/strong&gt;: &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;preEmit hook] componentMethod + msg --&amp;gt; componentProp [postRx hook&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;** How to think about this: the IO event is triggered by &lt;code&gt;componentMethod&lt;/code&gt;, and the event "componentMethod" gets sent with "msg" (defined in the component as &lt;code&gt;this.msg&lt;/code&gt;). When the server responds, the response goes to component's prop &lt;code&gt;componentProp&lt;/code&gt;. &lt;code&gt;preEmit&lt;/code&gt; hook is run before the event is sent, and &lt;code&gt;postRx&lt;/code&gt; hook is run after data is received. A nice thing here is the &lt;em&gt;plugin&lt;/em&gt; creates the &lt;code&gt;componentMethod&lt;/code&gt; for you so you don't have to. Just call it and it will work.&lt;/p&gt;

&lt;p&gt;→ The &lt;code&gt;preEmit&lt;/code&gt; and &lt;code&gt;postRx&lt;/code&gt; hooks are optional, but if using them, the "]" and "[" characters are needed so the plugin can parse them. These hooks would be defined in the component's methods section like &lt;code&gt;this.preEmit&lt;/code&gt; and &lt;code&gt;this.postRx&lt;/code&gt;&lt;br&gt;
→ The &lt;code&gt;msg&lt;/code&gt; is optional, but if using, must use the '+' character&lt;br&gt;
→ The &lt;code&gt;componentMethod&lt;/code&gt; is auto-created by the plugin and sends the event with the same name. If the &lt;code&gt;componentMethod&lt;/code&gt; is named "getMessage" it sends the event "getMessage"&lt;br&gt;
→ The &lt;code&gt;componentProp&lt;/code&gt; is optional, but if entered, will be the property that will get set with the response, if a response comes back. This is optional too, and needs to be initially defined on the component, otherwise it won't get set. Vuejs will also complain if you try to render undefined props. If &lt;code&gt;componentProp&lt;/code&gt; is omitted from the entry, the arrow "--&amp;gt;" can also be omitted.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Listeners&lt;/strong&gt;: &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;preHook] listenEvent --&amp;gt; componentProp [postRx hook&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;** How to think about this: when event "listenEvent" is received, the prop &lt;code&gt;this.componentProp&lt;/code&gt;will be set to that event's data. &lt;code&gt;preHook&lt;/code&gt; will run when data is received, but before setting &lt;code&gt;componentProp&lt;/code&gt;. &lt;code&gt;postRx&lt;/code&gt; hook will run after setting the &lt;code&gt;componentProp&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;→ Both &lt;code&gt;preHook&lt;/code&gt; and &lt;code&gt;postRx&lt;/code&gt; hooks are optional. Here, &lt;code&gt;preHook&lt;/code&gt; is called when data is received, but &lt;em&gt;before&lt;/em&gt; setting componentProp. &lt;code&gt;postRx&lt;/code&gt; hook is called after setting the prop. &lt;code&gt;this.preHook&lt;/code&gt; and &lt;code&gt;this.postRx&lt;/code&gt; would need to be defined in the component's methods section if planning to use either.&lt;br&gt;
→ If using the arrow syntax, when &lt;code&gt;listenEvent&lt;/code&gt; is received, &lt;code&gt;componentProp&lt;/code&gt; will get set with that event's data. If only the &lt;code&gt;listenEvent&lt;/code&gt; is entered, then the plugin will try to set a property on the component of the same name. I.e., if &lt;code&gt;listenEvent&lt;/code&gt; is "progressRxd", then the plugin will try to set &lt;code&gt;this.progressRxd&lt;/code&gt; on the component.&lt;br&gt;
→ Important NOTE: This syntax can now also work on the Vuex options for mutations and actions, which are also set up as listeners.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Emitbacks&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;preEmitHook] emitEvt &amp;lt;-- watchProp [postAck hook&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;** How to think about this: When a component's property &lt;code&gt;watchProp&lt;/code&gt; changes, emit back the event "emitEvt". &lt;code&gt;preEmitHook&lt;/code&gt; will run before the data is emitted, and &lt;code&gt;postAck&lt;/code&gt; will run after the server acknowledges its event, if any.&lt;/p&gt;

&lt;p&gt;→ &lt;code&gt;preEmitHook&lt;/code&gt; and &lt;code&gt;postAck&lt;/code&gt; hooks are optional. &lt;code&gt;preEmitHook&lt;/code&gt; runs before emitting the event, &lt;code&gt;postAck&lt;/code&gt; hook runs after receiving the acknolwedgement, if any. &lt;code&gt;this.preEmitHook&lt;/code&gt; and &lt;code&gt;this.postAck&lt;/code&gt; would need to be defined in the component's methods if planning to use.&lt;br&gt;
→ &lt;code&gt;watchProp&lt;/code&gt; is the property on the component to watch using "myObj.child.grandchild" syntax. Just like you would on the component. &lt;br&gt;
→ &lt;code&gt;emitEvt&lt;/code&gt; is the event name to emit back to the server when the &lt;code&gt;watchProp&lt;/code&gt; changes. If &lt;code&gt;watchProp&lt;/code&gt; and the arrow "&amp;lt;--" are omitted, then &lt;code&gt;emitEvt&lt;/code&gt; will double as the &lt;code&gt;watchProp&lt;/code&gt;. &lt;br&gt;
→ Important NOTE: this syntax can now also work in the Vuex options for emitbacks, with ONE important difference. In Vuex (and Nuxt, specifically), the watch property path may require forward slashes "/". For example, if your stores folder has an "examples.js" file in it, with state properties "sample" and "sample2", watchProp would have to be specified as "examples/sample" and "examples/sample2". The exception to the rule is "index.js" which is treated as the stores root. I.e., "sample" in index.js would be referred to simply as "sample" and not "index/sample")&lt;/p&gt;


&lt;h2&gt;
  
  
  Example Configuration
&lt;/h2&gt;

&lt;p&gt;Consider the following configuration as an example:&lt;br&gt;
In &lt;code&gt;nuxt.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespaces: {
  '/index': {
    emitters: ['getMessage2 + testMsg --&amp;gt; message2Rxd'],
    listeners: ['chatMessage2', 'chatMessage3 --&amp;gt; message3Rxd']
  },
  '/examples': {
    emitBacks: ['sample3', 'sample4 &amp;lt;-- myObj.sample4'],
    emitters: [
      'reset] getProgress + refreshInfo --&amp;gt; progress [handleDone'
    ],
    listeners: ['progress']
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;1) First, let's analyze the &lt;code&gt;/index&lt;/code&gt; config. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Emitters:&lt;br&gt;
When &lt;code&gt;getMessage()&lt;/code&gt; is called, the event "getMessage" will be sent with component's data &lt;code&gt;this.testMsg&lt;/code&gt;. &lt;code&gt;this.testMsg&lt;/code&gt; should be defined on the component, but if it isn't no message will get sent (the plugin will warn when the component data is not defined). When a response is received, &lt;code&gt;this.messageRxd&lt;/code&gt; on the component will get set to that response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Listeners: &lt;br&gt;
When &lt;code&gt;chatMessage2&lt;/code&gt; is received, &lt;code&gt;this.chatMessage2&lt;/code&gt; on the component will be set. When &lt;code&gt;chatMessage3&lt;/code&gt; is received, the mapped property &lt;code&gt;this.message3Rxd&lt;/code&gt; will be set.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) Let's analyze the &lt;code&gt;/examples&lt;/code&gt; config.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Emitbacks: &lt;br&gt;
When &lt;code&gt;this.sample3&lt;/code&gt; changes in the component, the event &lt;code&gt;sample3&lt;/code&gt; will be emitted back to the server. When &lt;code&gt;this.myObj.sample4&lt;/code&gt; changes in the component, the mapped event &lt;code&gt;sample4&lt;/code&gt; will be emitted back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emitters:&lt;br&gt;
When &lt;code&gt;this.getProgress()&lt;/code&gt; is called, &lt;em&gt;first&lt;/em&gt; &lt;code&gt;this.reset()&lt;/code&gt; will be called (if it's defined) and &lt;em&gt;then&lt;/em&gt; the event "getProgress" will be emitted with the message &lt;code&gt;this.refreshInfo&lt;/code&gt;. When the response is received, &lt;code&gt;this.progress&lt;/code&gt; will get set to the response, and then &lt;code&gt;this.handleDone()&lt;/code&gt; will be called (if it's defined)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Listeners:&lt;br&gt;
When event "progress" is received, &lt;code&gt;this.progress&lt;/code&gt; will get set to that data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Chat rooms: a more exciting example
&lt;/h2&gt;

&lt;p&gt;Want to see a slightly more exciting example? Check out my [very basic] chat rooms example!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone my git repo: &lt;a href="https://github.com/richardeschloss/nuxt-socket-io"&gt;https://github.com/richardeschloss/nuxt-socket-io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run the server with &lt;code&gt;npm run dev:server&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to the chat rooms page at: &lt;a href="https://localhost:3000/rooms"&gt;https://localhost:3000/rooms&lt;/a&gt; and have fun!
(open two browser windows because...you need at least two clients to have a conversation; you can also chat with yourself, if you want :))&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My next article in this series should help explain that example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This was a rather lengthy, but important, discussion of nuxt-socket-io's new namespace configuration feature. While the time spent reading this article may have been longer than desired, it is very possible that the time spent on your future web applications will be significantly reduced by taking advantage of what you learned here. It may be a bumpy road at first, but I think over time, you'll get used to the syntax. If you hate it, no worries...the plugin will still expose the socket.io client API directly, so your fingertips will have that if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits / Acknowledgement
&lt;/h2&gt;

&lt;p&gt;Thanks to Ofoe Apronti &lt;a href="https://github.com/OfoeApronti"&gt;@OfoeApronti&lt;/a&gt; for opening the issue and asking about it. At first, I didn't think there was a clean way to create this feature, and gave up on it early. But, with more thought put into it, I think the solution may end up satisfying most users (fingers crossed).&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>javascript</category>
      <category>easy</category>
    </item>
    <item>
      <title>Introducing Lesky: The Multi-lingual CLI for Rapidly Starting KoaJS-based Applications</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Tue, 17 Dec 2019 22:51:24 +0000</pubDate>
      <link>https://forem.com/richardeschloss/introducing-lesky-the-multi-lingual-cli-for-rapidly-starting-koajs-based-applications-1ckl</link>
      <guid>https://forem.com/richardeschloss/introducing-lesky-the-multi-lingual-cli-for-rapidly-starting-koajs-based-applications-1ckl</guid>
      <description>&lt;p&gt;TL;DR - &lt;a href="https://www.npmjs.com/package/lesky"&gt;Lesky&lt;/a&gt; is meant to be a relatively lightweight multi-lingual CLI that gets installed once (globally) and used anywhere, invoked with &lt;code&gt;les&lt;/code&gt; (not more, because &lt;code&gt;les&lt;/code&gt; is less). Specifically, any folder can be statically served and watched for changes. Also, any folder can be initialized as a KoaJS-based app rapidly using the CLI. It's as if &lt;code&gt;http-server&lt;/code&gt; and &lt;code&gt;express-generator&lt;/code&gt; gave birth to a ES6-based mutli-lingual baby. This baby knows 42 different languages.&lt;/p&gt;

&lt;p&gt;Disclaimer: I am the author of lesky.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Many problems that lesky intends to solve are solved pretty well by other great,  but separate, projects. However, the goal with lesky was to bring a lot of great ideas together in one package to solve the following problems, while requiring less effort from the user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run it anywhere on the machine to serve static content. Sometimes I require or prefer fiddling locally on machine rather than online, since it's usually much faster.&lt;/li&gt;
&lt;li&gt;Support all http protocols (http, https, http2), not just http (old as 1995!). http3 is on the radar. &lt;/li&gt;
&lt;li&gt;Consume a configuration file of server configs (so I don't have to type it in again)&lt;/li&gt;
&lt;li&gt;Immediately open the default browser and watch for file changes&lt;/li&gt;
&lt;li&gt;Disable cache-control by default, since it's a dev server and I want to see the changes as I make them.&lt;/li&gt;
&lt;li&gt;Separate the concerns of the server from the application, database, IO, and CLI. This way, if the server has to be changed out with a different version of Koa, or a different server framework, it should be easy enough to do so.&lt;/li&gt;
&lt;li&gt;Initialize any workspace with KoaJS boilerplate, while still separating the concerns of the server and app. Ideally, the workspace would be initialized with eslint, babel, test framework and other configuration files so that it would be ready to go. Those extras add a bit of weight to the project, but I think it's worth it. (I wanted something like express-generator, but less typing, and less code to refactor based on my personal preferences)&lt;/li&gt;
&lt;li&gt;It had to be reusable and have reusable utils. More of those utils can be found in &lt;a href="https://www.npmjs.com/package/les-utils"&gt;&lt;code&gt;les-utils&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;It had to be mutli-lingual because I think people will think the best when they are able to use it in their native language. This was the most challenging task, but worth doing, I think.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installing:
&lt;/h2&gt;

&lt;p&gt;It is recommended to install lesky globally so you don't have to do it again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm i -g lesky&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you do not currently have your npm global path searchable, you simply need to update your PATH environment variable: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;export PATH=~/.npm-global/bin:$PATH&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Important note: even though the project is called "lesky", the command will be "les". "les" was desired for the project name, but taken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Usage:
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;les [path] [options]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, for example, simply typing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;les&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;this will serve static content that is in the "public" folder (If you run the command from /myproject, then /myproject/public needs to exist; if it doesn't simply create it or specify the path you want to serve)&lt;/p&gt;

&lt;p&gt;To quickly see the application, it's simply a matter of: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;les -ow # "less ouch", get it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The 'o' opens the browser, and the 'w' watches for file changes. It may help to include my &lt;a href="https://raw.githubusercontent.com/richardeschloss/les/master/public/webpack/dumbReloader.slim.js"&gt;dumb reloader script&lt;/a&gt; in the html file you wish to auto reload on changes. This is nowhere near as cool as hot module reloading, but it's good enough for quick-and-dirty development work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Lesky
&lt;/h2&gt;

&lt;p&gt;Making lesky easy to configure was one of the key goals, and built on a CLI-design pattern that seems to be common today. The pattern is: allow CLI arguments to come first from a configuration &lt;em&gt;file&lt;/em&gt; and then if arguments are &lt;em&gt;also passed in&lt;/em&gt; on the command line, give priority to those arguments. This pattern makes it real easy to "code with config" and at the same time, overwrite the config on the command line when needed, without actually changing the config file.&lt;/p&gt;

&lt;p&gt;The CLI options can always be found in the help menu:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;les -h&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usage: les [path] [options]

options:
    -h, --help  Print this help menu
    -i, --init  Init lesky in workspace specified by path, defaults to cwd [[cwd]]
    -a, --host  Address to use [localhost]
    -p, --port  Port to use [8080]
        --proto Protocol to use [http] ({ http, https, http2 })
        --range Port Range (in case port is taken) [8000,9000]
        --sslKey    Path to SSL Key
        --sslCert   Path to SSL Certificate
    -o, --open  Open browser [OS default]
    -w, --watch Watch for file changes in dir [staticDir]

---End of Help---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that any of the long-form options shown here can be entered in the terminal &lt;em&gt;or&lt;/em&gt; in the config file:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;les --port 8001&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Is equivalent to having a les config file (&lt;code&gt;.lesrc&lt;/code&gt;) with the entry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[{ "port": 8001 }]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, simply typing &lt;code&gt;les&lt;/code&gt; will start the server at the configured port 8001. There are important things to note with the config file and the CLI. In the config file, the structure is an array of server configs. This way, if you want to host the "http" version at port 8001, and the "https" version at port 8002, this config file is all that you need! No extra changes to code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[{
  "host": "localhost",
  "proto": "https",
  "port": 8002,
  "sslKey": ".ssl/server.key",
  "sslCert": ".ssl/server.crt"
},{
  "proto": "http",
  "port": 8001
}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important notes and limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The configuration file is the only way to specify multiple server configs. I.e., &lt;code&gt;les --proto http --proto https&lt;/code&gt; may not do what you think it will.&lt;/li&gt;
&lt;li&gt;The configuration file requires the long-form option names, not the aliases. The aliases are only respected in the terminal. The reason is, I wanted this file to support multiple languages. The aliases are fixed, but the long-form option names are changed based on user locale. I think this design choice may result in a better developer experience. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Initializing a workspace
&lt;/h2&gt;

&lt;p&gt;More than likely, it will be desired to create a custom lesky-based / KoaJS-based application in the folder you are currently working in. You'll want to do more than serve static content. This is pretty simple to do with &lt;code&gt;les&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;les [path] --init [options]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Where path specifies the directory to initialize (defaults to the current working directory). Any options that get passed in at this step will be used to auto-generate the &lt;code&gt;.lesrc&lt;/code&gt; config file so you'll never have to enter it again. Just consume it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-lingual support
&lt;/h2&gt;

&lt;p&gt;The tool currently supports 42 different languages. In order for it to work correctly, it expects the "LANG" environment variable to be set and to include the language's 2-character code. For example, on my system, it's "en_US.UTF-8" (char code == "en"). Lesky will attempt to parse that 2-character code and work in your system's language. If that variable is not set, it's easy enough to specify:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LANG="es" les --ayudar&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;el uso de: les [path] [options]

options:
    -h, --ayuda Imprime este menú de ayuda
    -i, --init  Init lesky en el espacio de trabajo especificado por la ruta por defecto cwd [[cwd]]
    -a, --host  Dirección [localhost]
    -p, --puerto    El puerto a utilizar [8080]
        --proto Protocolo para el uso de [http] ({ http, https, http2 })
        --range Rango de puertos (en caso de que el puerto se toma). Formato de inicio-final [8000,9000]
        --sslKey    Ruta de acceso de la Clave SSL
        --sslCert   Ruta de acceso a los Certificados SSL
    -o, --abierto   Abra el navegador. [OS default]
    -w, --reloj Reloj para los cambios de los archivos en el directorio [staticDir]

---Fin de Ayudar a---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now, the person who knows Spanish can use the tool, without having to think in English! So, this means &lt;code&gt;.lesrc&lt;/code&gt; can be written like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[{ "puerto": 8080 }] // Here, either "port" or "puerto" will work. English is the fall-back
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, maybe someone speaks French and wants to run the tool. That's easy too:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LANG="fr" les -ow&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Options for locale fr does not exist, will attempt to download
res.statusCode 200
listening at: (proto = http, host = localhost, port = 8020)
navigateur ouvert
servir statique dir public
Serveur tous les configs commencé
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: some English is still mixed in to the console messages, but it is my hope and understanding that the user will see the key messages being translated and still understand the numbers in the English messages. I also hope that the translations are all correct. This was no easy task, even with the help of AI. I will plan to discuss that adventure in perhaps another article. (&lt;a href="https://github.com/richardeschloss/les/"&gt;PRs&lt;/a&gt; are welcome if I translated incorrectly!)&lt;/p&gt;

&lt;p&gt;Small digression: I'm most proud of this feature because it was the most challenging, but I think it was definitely worth doing. This is my attempt to challenge the phrase "code in English". I can't imagine how difficult my development workflow would be if I had to think in a non-native language. So hopefully, a world of people will find this useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Lesky was designed to help make your life insanely easier, with regards to serving static content and initializing new projects. Separation of server logic from all other logic was meant to free the user from "server lock-in" if it ever needed to be changed out. Mutli-lingual support was added to make it accessible. I hope you find it helpful. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>koajs</category>
      <category>cli</category>
      <category>lightweight</category>
    </item>
    <item>
      <title>How I Learned GraphQL Thinking Like a 5 yr old</title>
      <dc:creator>Richard Schloss</dc:creator>
      <pubDate>Wed, 04 Dec 2019 20:53:24 +0000</pubDate>
      <link>https://forem.com/richardeschloss/how-i-learned-graphql-thinking-like-a-5-yr-old-1jcc</link>
      <guid>https://forem.com/richardeschloss/how-i-learned-graphql-thinking-like-a-5-yr-old-1jcc</guid>
      <description>&lt;h1&gt;
  
  
  Preface
&lt;/h1&gt;

&lt;p&gt;We often hear the phrase, "explain it to me like I'm 5". Even yesterday, I came across an interesting dev.to post with that headline. For a while now, I've been meaning to write about &lt;em&gt;flipping&lt;/em&gt; that phrase to "think about it like you're 5". 5 year olds can be fantastic learners, and can be experts at thinking in simple terms. Their terseness allows them to be extremely efficient and effective at getting exactly what they want.&lt;/p&gt;

&lt;p&gt;As we all get older, our language skills improve, and we all concern ourselves with formalities and mannerisms. So, if we see a friend eating a candy bar, and we want it, we ask:&lt;/p&gt;

&lt;p&gt;"Hi, how are you doing? That candy bar looks delicious? May I please have a piece?"&lt;/p&gt;

&lt;p&gt;The child, on the other hand, just says:&lt;/p&gt;

&lt;p&gt;"Candy bar!"&lt;/p&gt;

&lt;p&gt;Even if the adult holding the candy bar replies, "What do you say?" the child still says "Candy bar!". The adult replies, "You say please" (and still gives the child the candy bar anyway!) and the child laughs, "No, you say please".&lt;/p&gt;

&lt;p&gt;The adult has to be concerned with formalities since it is a way of showing respect to other people. The adult knows that if he doesn't show respect in asking his question, he may end up empty-handed...and possibly receive a reply along the lines of "heck no". The child on the other hand gets a free pass, because he may not know any better at that point in time. Lucky kid!&lt;/p&gt;

&lt;p&gt;It seems like this adult-way of thinking sometimes carries over into the way we program, and can make us less efficient, making us way too concerned with the framing of a message when it is only the data we are really concerned about. We may forget that when we talk to a machine, and not a human being, we can worry less about mannerisms, and just tell the machine what we want.&lt;/p&gt;

&lt;h1&gt;
  
  
  Approaching GraphQL like a 5 year old
&lt;/h1&gt;

&lt;p&gt;When I first glanced at GraphQL, it seemed attractive that, as a developer, I could focus primarily on the data and less on the formalities to get that data (because writing laundry lists of API routes was never the job I signed up for). I was also a bit intimidated because I wasn't entirely sure if I was ready to take on a completely different way of thinking. Luckily, the "completely different way of thinking" actually required me to simplify my mind to that of a 5 year old's. &lt;/p&gt;

&lt;p&gt;Let's carry over the "candy bar" example to here to explain how thinking like a child makes life easier.&lt;/p&gt;

&lt;p&gt;An adult brain coming from RESTful APIs will probably think in terms like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http.get('/?candybar=kitkat&amp;amp;size=kingSize').then(handleResp)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The adult has to concern himself with the protocol "http", the special characters "&amp;amp;", "=" and know how to position those correctly. And must remember the ".then". &lt;/p&gt;

&lt;p&gt;An adult from an SQL-mindset will probably structure the query like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM CANDYBARS WHERE CANDYBAR="kitkat" AND SIZE="kingSize"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The adult has to concern herself with table names and column names. The adult has to be aware of the &lt;em&gt;tabular&lt;/em&gt; structure of the data. It's a lot of typing to get just one candybar. Oh, and the words "SELECT", "WHERE", "FROM", "AND"...that's all English...so, if English is not the adult's native language, the query just became a little more difficult for her to understand...&lt;/p&gt;

&lt;p&gt;A child on the other hand would probably just ask for the candy asap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;candybar = 'kitkat'
size = 'kingSize'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much simpler, right?? Now, this snippet is not actually GraphQL, but it is pretty close. This is how I started learning. My thought process at the time was, "ok GraphQL, you say you're just about the data, we'll make it just about that." I'll evolve my query just a bit to match what I think a JSON-like query should look like, because I think that's what you'd expect: perhaps some curly braces and a comma&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  candybar: 'kitkat',
  size: 'kingSize'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Er...on second thought...omit the comma because a 5 year old may not always be so concerned about punctuation as much as efficiency. &lt;/p&gt;

&lt;p&gt;With a mental paradigm in place, it was time for me to do the other thing a 5 year-old does best: play with it. Fortunately, the online tool &lt;a href="https://graphiql-test.netlify.com/"&gt;Interactive GraphQL "GraphiQL"&lt;/a&gt; was extremely invaluable. No setup or authentication required. All I had to do was just browse to it and it was ready for my input.&lt;/p&gt;

&lt;p&gt;In that playground, I was able to try the above snippet in the coding pane and realize right away the syntax was off. The "result" pane told me what errors there were, and further poking around to the top right corner revealed what Schemas were available. So, eventually, with just a few modifications (and yes, reading the docs), I learned that the above query would be need to be written like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ // &amp;lt;-- NOTE: the word "query" is optional and can be omitted; GraphQL treats this as a query by default. Pretty cool, right?
  candyBars (candyBar: 'kitkat', size: 'kingSize') { // &amp;lt;-- query params
    candyBar // &amp;lt;-- include in resp back to me
    size // &amp;lt;-- include in resp back to me
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, a 5 year old may want even more information, even though the actual parameters would remain unchanged. This was easy to do in GraphQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  candyBars (candyBar: 'kitkat', size: 'kingSize') { // &amp;lt;-- query params
    id // &amp;lt;-- Makes life easier. See mutations below.
    candyBar
    size
    /* Extra props here: */
    shape // 'rectangle'
    wrapperColor // 'red'
    wrapperHasCartoon // true
    /* &amp;lt;-- keep typing...GraphiQL has intellisense... --&amp;gt; */
    /* type until you get the prop you want. */
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This addresses the querying, but what about changing the state of the candy bar? The 5 year old may want to bite off a good chunk. So, my thinking originally was something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;update (id: 123, pctBitten: "50%") {
  size // respond with new size
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, in GraphQL, the word isn't "update" it is "mutation". With a little extra tweaking, the snippet just becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  biteCandyBar(id: 123, pct: "50%") { // mutations are labeled
    size // respond with new size
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the word "mutation" is a bit more typing than "update", and may even be out of the scope of a 5 year old's vocabulary, the block inside the mutation may be closer to a 5 year old's thinking. I.e., the mutation to be performed is "biteCandyBar". This also lets the parameter be simplified from "pctBitten" to "pct". It's inferred that "pct" refers to the "pctBitten" because of the mutation's label.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Ok yes, there is a lot more to GraphQL than what I described. This just scratches the surface and to become an expert with it, the responsible developer will probably read the docs comprehensively. However, to get your feet wet, I implore you to think like you are 5! It may just very well reduce whatever fear you might initially have with approaching this new query language.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>apollo</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
