<?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>DEV Community: Calvin Nguyen</title>
    <description>The latest articles on DEV Community by Calvin Nguyen (@calvinqc).</description>
    <link>https://dev.to/calvinqc</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%2F347104%2F8ea80744-6113-4443-984d-7392b8076f96.png</url>
      <title>DEV Community: Calvin Nguyen</title>
      <link>https://dev.to/calvinqc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/calvinqc"/>
    <language>en</language>
    <item>
      <title>I tried Github CLIs...and I never open browser again!</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Sun, 30 Aug 2020 03:26:51 +0000</pubDate>
      <link>https://dev.to/calvinqc/save-more-time-with-github-cli-gh-pr-create-2bb8</link>
      <guid>https://dev.to/calvinqc/save-more-time-with-github-cli-gh-pr-create-2bb8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I added #discuss, so please if anyone of you knows new features of Github CLIs, feel free to comment. Below, I found more cool things I could do with &lt;code&gt;gh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JPO0sc55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2A_Gp8d1a15_03NZLb" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JPO0sc55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2A_Gp8d1a15_03NZLb" alt="https://cdn-images-1.medium.com/max/1600/0*_Gp8d1a15_03NZLb"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Inspiration
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GitHub tools are all great, but sometimes, I get exhausted as I’m coding and have to switch from my terminal/text editor to do many clicks in the browser, just to create or view a PR.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Luckily, on March 6th, 2020, GitHub released a new &lt;strong&gt;cool GitHub CLI&lt;/strong&gt; to create PR/ Issue in your local terminal.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, I will go over 1 main command that I usually daily and highly recommend: &lt;strong&gt;&lt;code&gt;gh pr &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Installment&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;macOS&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Easy Install With brew: &lt;code&gt;$ brew install github/gh/gh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Upgrade: &lt;code&gt;brew update &amp;amp;&amp;amp; brew upgrade gh&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Windows&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Install &lt;code&gt;gh&lt;/code&gt; via &lt;strong&gt;&lt;a href="https://scoop.sh/"&gt;Scoop&lt;/a&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;scoop bucket add github-gh https://github.com/cli/scoop-gh.git
scoop &lt;span class="nb"&gt;install &lt;/span&gt;gh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Linux&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For Linux and other platforms, please refer to this &lt;a href="https://github.com/cli/cli/releases/tag/v0.6.1"&gt;GitHub page&lt;/a&gt; for different installment&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Normal flow vs. new Github CLI&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Old Process of creating a PR:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(feat/login)$ git add .&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(feat/login)$ git commit -m "init skeleton code for login"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(feat/login)$ git push origin feat/login&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open Github on browser&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open Github project&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;code&gt;Create a PR&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fill the title and body&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Now, let's see how many steps when we use &lt;code&gt;gh pr create&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(feat/login)$ git add .&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(feat/login)$ git commit -m "init skeleton code for login"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;feat/login&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create
Enumerating objects: 9, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;9/9&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Delta compression using up to 4 threads
Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;5/5&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Writing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;5/5&lt;span class="o"&gt;)&lt;/span&gt;, 444 bytes | 444.00 KiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Total 5 &lt;span class="o"&gt;(&lt;/span&gt;delta 4&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;
remote: Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;4/4&lt;span class="o"&gt;)&lt;/span&gt;, completed with 4 &lt;span class="nb"&gt;local &lt;/span&gt;objects.
To github.com:calvinqc/trivin.git
   1c179cb..7953ecc  HEAD -&amp;gt; gh-testing
Branch &lt;span class="s1"&gt;'feat/login'&lt;/span&gt; &lt;span class="nb"&gt;set &lt;/span&gt;up to track remote branch &lt;span class="s1"&gt;'feat/login'&lt;/span&gt; from &lt;span class="s1"&gt;'origin'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Creating pull request &lt;span class="k"&gt;for &lt;/span&gt;feat/login into master &lt;span class="k"&gt;in &lt;/span&gt;calvinqc/trivin
? Title &lt;span class="o"&gt;[&lt;/span&gt;WIP] Login API
? Body &amp;lt;Received&amp;gt;
? What&lt;span class="s1"&gt;'s next? Submit
https://github.com/calvinqc/trivin/pull/1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Options&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Source from &lt;a href="https://cli.github.com/manual/gh_pr_create"&gt;Github CLIs&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nt"&gt;-a&lt;/span&gt;, &lt;span class="nt"&gt;--assignee&lt;/span&gt; login   Assign people by their login
  &lt;span class="nt"&gt;-B&lt;/span&gt;, &lt;span class="nt"&gt;--base&lt;/span&gt; string      The branch into which you want your code merged
  &lt;span class="nt"&gt;-b&lt;/span&gt;, &lt;span class="nt"&gt;--body&lt;/span&gt; string      Supply a body. Will prompt &lt;span class="k"&gt;for &lt;/span&gt;one otherwise.
  &lt;span class="nt"&gt;-d&lt;/span&gt;, &lt;span class="nt"&gt;--draft&lt;/span&gt;            Mark pull request as a draft
  &lt;span class="nt"&gt;-f&lt;/span&gt;, &lt;span class="nt"&gt;--fill&lt;/span&gt;             Do not prompt &lt;span class="k"&gt;for &lt;/span&gt;title/body and just use commit info
  &lt;span class="nt"&gt;-l&lt;/span&gt;, &lt;span class="nt"&gt;--label&lt;/span&gt; name       Add labels by name
  &lt;span class="nt"&gt;-m&lt;/span&gt;, &lt;span class="nt"&gt;--milestone&lt;/span&gt; name   Add the pull request to a milestone by name
  &lt;span class="nt"&gt;-p&lt;/span&gt;, &lt;span class="nt"&gt;--project&lt;/span&gt; name     Add the pull request to projects by name
  &lt;span class="nt"&gt;-r&lt;/span&gt;, &lt;span class="nt"&gt;--reviewer&lt;/span&gt; login   Request reviews from people by their login
  &lt;span class="nt"&gt;-t&lt;/span&gt;, &lt;span class="nt"&gt;--title&lt;/span&gt; string     Supply a title. Will prompt &lt;span class="k"&gt;for &lt;/span&gt;one otherwise.
  &lt;span class="nt"&gt;-w&lt;/span&gt;, &lt;span class="nt"&gt;--web&lt;/span&gt;              Open the web browser to create a pull request
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Easy 1 line command:&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;create &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"[WIP] Login API"&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="s2"&gt;"Init skeleton code for Login API"&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"calvinqc"&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"feat"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Roadmap"&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;$ &lt;/p&gt;

&lt;p&gt;If there’s one thing that I love about &lt;code&gt;gh pr create&lt;/code&gt;, it is that it will &lt;strong&gt;push + create a PR at the same time&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;List all PRs&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;list
Pull requests &lt;span class="k"&gt;for &lt;/span&gt;calvinqc/trivin
&lt;span class="c"&gt;#2  [WIP] Register API  feat/register&lt;/span&gt;
&lt;span class="c"&gt;#1  [WIP] Login API     feat/login&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;View a PR&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;view 1
Opening https://github.com/calvinqc/trivin/pull/1 &lt;span class="k"&gt;in &lt;/span&gt;your browser
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Get status of all PRs&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;status
Relevant pull requests &lt;span class="k"&gt;in &lt;/span&gt;calvinqc/trivin
Current branch
  &lt;span class="c"&gt;#1  [WIP] Login API     feat/login&lt;/span&gt;
   - Checks passing
Created by you
  &lt;span class="c"&gt;#2  [WIP] Register API  feat/register&lt;/span&gt;
   - Checks passing
  &lt;span class="c"&gt;#1  [WIP] Login API     feat/login&lt;/span&gt;
   - Checks passing
Requesting a code review from you
  You have no pull requests to review
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Checkout a PR&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is very similar to a regular branch checkout, but I don't have to checkout and then pull the code from that branch&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;checkout 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Let's connect
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://linktr.ee/calvinqc"&gt;https://linktr.ee/calvinqc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>github</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>A Step-by-Step Guide to Setting Up a Node.js API With Passport-JWT</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Sat, 22 Aug 2020 21:37:56 +0000</pubDate>
      <link>https://dev.to/calvinqc/a-step-by-step-guide-to-setting-up-a-node-js-api-with-passport-jwt-5fa5</link>
      <guid>https://dev.to/calvinqc/a-step-by-step-guide-to-setting-up-a-node-js-api-with-passport-jwt-5fa5</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F1200%2F0%2AdPh6-JVay7r7HlJV.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%2Fcdn-images-1.medium.com%2Fmax%2F1200%2F0%2AdPh6-JVay7r7HlJV.png" alt="https://cdn-images-1.medium.com/max/1200/0*dPh6-JVay7r7HlJV.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authentication and authorization are a huge part of applications. Whenever there’s an API route without protection or checks, an application can easily become a target for hackers. That’s why we need a secure token — the &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JSON Web Token (JWT)&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;The Basics of JWT&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;I will not go too deeply into JWT, but here are all the basics.&lt;/em&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aa5Oo7gACg1vPfTMo.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aa5Oo7gACg1vPfTMo.png" alt="https://cdn-images-1.medium.com/max/800/0*a5Oo7gACg1vPfTMo.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;JSON web tokens encode and decode your user’s info. They’re used for authorization and information exchange.&lt;/p&gt;

&lt;p&gt;They consist of three parts — header, payload, and signature — separated by dots (&lt;code&gt;.&lt;/code&gt;) like this: &lt;code&gt;xxxxx.yyyyy.zzzzz&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Read more about JSON web tokens &lt;a href="https://jwt.io/introduction/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Before You Begin&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;I’ll assume your computer already has &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt; and testing with Postman, if not check out this &lt;a href="https://www.youtube.com/watch?v=t5n07Ybz7yI&amp;amp;feature=emb_logo" rel="noopener noreferrer"&gt;video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the &lt;a href="https://github.com/calvinqc/trivin/tree/master/templates/node-passport-jwt" rel="noopener noreferrer"&gt;code&lt;/a&gt; if you have any trouble with the process and join Trivin’s &lt;a href="https://trivin.slack.com/" rel="noopener noreferrer"&gt;slack&lt;/a&gt; if you need to ask any questions.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Server Setup&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Skip this step if you prefer to use your own server.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you don’t have a project, we’ll use &lt;a href="https://github.com/calvinqc/trivin" rel="noopener noreferrer"&gt;Trivin&lt;/a&gt; to set up project templates. In this article, we’ll use it to create a simple-node-server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i trivin -g
$ trivin server simple-node-server -g -i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create &lt;a href="https://medium.com/swlh/a-complete-guide-build-a-scalable-3-tier-architecture-with-mern-stack-es6-ca129d7df805" rel="noopener noreferrer"&gt;a simple but well-structured node-server&lt;/a&gt;, initialize Git, and install all the project dependencies.&lt;/p&gt;




&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i passport passport-jwt winston cors express-validator jsonwebtoken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Supporting Files Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir store/ 
$ touch store/passport.js store/config.js store/utils.js controller/constant.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Constant.js
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;First, there’s something I really like to do in the constant.js file. Instead of writing a lot of strings, I create &lt;em&gt;variables&lt;/em&gt; for strings that I’m likely to re-use.&lt;/li&gt;
&lt;li&gt;Allow &lt;code&gt;TextEditor&lt;/code&gt; to auto-complete for me and reduce typos in strings.&lt;/li&gt;
&lt;li&gt;Add these to the &lt;code&gt;constant.js&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ul&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EMAIL_IS_EMPTY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EMAIL_IS_EMPTY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PASSWORD_IS_EMPTY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PASSWORD_IS_EMPTY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PASSWORD_LENGTH_MUST_BE_MORE_THAN_8&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PASSWORD_LENGTH_MUST_BE_MORE_THAN_8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WRONG_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WRONG_PASSWORD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SOME_THING_WENT_WRONG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SOME_THING_WENT_WRONG&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USER_EXISTS_ALREADY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USER_EXISTS_ALREADY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USER_DOES_NOT_EXIST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USER_DOES_NOT_EXIST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TOKEN_IS_EMPTY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TOKEN_IS_EMPTY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EMAIL_IS_IN_WRONG_FORMAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EMAIL_IS_IN_WRONG_FORMAT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;utils.js&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A file that stores all the functions and validations that are used throughout the project.&lt;/li&gt;
&lt;li&gt;It makes your code in the API Controller files much cleaner.
&lt;/li&gt;
&lt;/ul&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;sha256&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;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="p"&gt;}&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;express-validator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;PASSWORD_IS_EMPTY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;PASSWORD_LENGTH_MUST_BE_MORE_THAN_8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;EMAIL_IS_EMPTY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;EMAIL_IS_IN_WRONG_FORMAT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&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;./constant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateHashedPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateServerErrorCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fullError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fullError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;fullError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;errors&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;span class="c1"&gt;// ================================&lt;/span&gt;
&lt;span class="c1"&gt;// Validation:&lt;/span&gt;
&lt;span class="c1"&gt;// Handle all validation check for the server&lt;/span&gt;
&lt;span class="c1"&gt;// ================================&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registerValidation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_IS_EMPTY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_IS_IN_WRONG_FORMAT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&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="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD_IS_EMPTY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLength&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD_LENGTH_MUST_BE_MORE_THAN_8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loginValidation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_IS_EMPTY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_IS_IN_WRONG_FORMAT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&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="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD_IS_EMPTY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLength&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PASSWORD_LENGTH_MUST_BE_MORE_THAN_8&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;
  
  
  &lt;strong&gt;Passport.js Setup&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A node.js library that helps you with the authentication.&lt;/li&gt;
&lt;li&gt;Add this to your &lt;code&gt;store/passport.js&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Strategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ExtractJwt&lt;/span&gt; &lt;span class="p"&gt;}&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;passport-jwt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;underscoreId&lt;/span&gt; &lt;span class="p"&gt;}&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;./config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&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;../database/models&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;applyPassportStrategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;passport&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jwtFromRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ExtractJwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAuthHeaderAsBearerToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secretOrKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Strategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;underscoreId&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&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;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;ul&gt;
&lt;li&gt;
&lt;code&gt;store/config.js&lt;/code&gt; is where I keep all of my configurations of the app:
&lt;/li&gt;
&lt;/ul&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;Add_Your_Own_Secret_Key&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mongoDBUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb://localhost/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mongoHostName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod&lt;/span&gt;&lt;span class="dl"&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;mongodbAtlas&lt;/span&gt;&lt;span class="dl"&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;localhost&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;underscoreId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify &lt;code&gt;app.js&lt;/code&gt; to use it with passport:&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;express&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;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;logger&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;winston&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&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;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cors&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;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;passport&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;passport&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mongoose&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;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&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;./store/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;applyPassportStrategy&lt;/span&gt; &lt;span class="p"&gt;}&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;./store/passport&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userController&lt;/span&gt; &lt;span class="p"&gt;}&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;./controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Set up CORS&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Apply strategy to passport&lt;/span&gt;
&lt;span class="nf"&gt;applyPassportStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// API Route&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Get port from environment and store in Express.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mongoDBUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mongoHostName&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Started successfully server at port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;mongoose&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mongoDBUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;useNewUrlParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useUnifiedTopology&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Conneted to mongoDB at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;mongoHostName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;h1&gt;
  
  
  &lt;strong&gt;Run Your App&lt;/strong&gt;
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s now go back and improve &lt;code&gt;user.controller.js&lt;/code&gt; by applying &lt;code&gt;passport-jwt&lt;/code&gt; to our API.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Apply Passport-jwt to Register/Login API&lt;/strong&gt;
&lt;/h1&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A1d_RhWhLZJvy0WFk.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A1d_RhWhLZJvy0WFk.png" alt="https://cdn-images-1.medium.com/max/800/0*1d_RhWhLZJvy0WFk.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image Source: dotnettricks.com&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;express&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;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwt&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;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;validationResult&lt;/span&gt; &lt;span class="p"&gt;}&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;express-validator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&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;../store/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;generateHashedPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;generateServerErrorCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;registerValidation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loginValidation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&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;../store/utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;SOME_THING_WENT_WRONG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;USER_EXISTS_ALREADY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;WRONG_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;USER_DOES_NOT_EXIST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&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;../store/constant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;}&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;../database/models&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hashedPassword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;generateHashedPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * GET/
 * retrieve and display all Users in the User Model
 */&lt;/span&gt;
&lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&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;span class="cm"&gt;/**
 * POST/
 * Register a user
 */&lt;/span&gt;
&lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;registerValidation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorsAfterValidation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validationResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;errorsAfterValidation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;errorsAfterValidation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapped&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;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Sign token&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toJSON&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;...{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;userToReturn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hashedPassword&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userToReturn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;generateServerErrorCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;register email error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;USER_EXISTS_ALREADY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;generateServerErrorCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SOME_THING_WENT_WRONG&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;span class="cm"&gt;/**
 * POST/
 * Login a user
 */&lt;/span&gt;
&lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loginValidation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorsAfterValidation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validationResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;errorsAfterValidation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;errorsAfterValidation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapped&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPasswordMatched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comparePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isPasswordMatched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Sign token&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userToReturn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toJSON&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;...{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;userToReturn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hashedPassword&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userToReturn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;generateServerErrorCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login password error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WRONG_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&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;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;generateServerErrorCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login email error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;USER_DOES_NOT_EXIST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Instead of using the user’s email and hashed password for authorization, which may not be secured during the communication between the client and the server.&lt;/li&gt;
&lt;li&gt;We use the JWT token for authorization. This way, we can ensure the security of the password and user’s email to be encrypted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Testing&lt;/strong&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;At this point, I’ll assume that you know how to use Postman.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;POST/&lt;/code&gt; method and enter &lt;code&gt;localhost:8080/register&lt;/code&gt; and &lt;code&gt;localhost:8080/login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After you test your Register API, you’ll successfully get a result similar to below. Copy the token to your clipboard.&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AEuWQ1Mo_cJwQzsI_V2rSRQ.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AEuWQ1Mo_cJwQzsI_V2rSRQ.png" alt="https://cdn-images-1.medium.com/max/800/1*EuWQ1Mo_cJwQzsI_V2rSRQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Register API Successful return a token and user’s email + id&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Authorization&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Let’s see if you want to go to a specific link that requires the user to login. Then, you can simply add an authorization in the API.&lt;/p&gt;

&lt;p&gt;Let’s look at an example.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;user.controller.js&lt;/code&gt;, I include a simple &lt;code&gt;'/'&lt;/code&gt; API that retrieves the list of all users — but I don’t want to retrieve all the users unless I log in as a user.&lt;/li&gt;
&lt;li&gt;Another example is Facebook. If you want to go to the news feed and retrieve all your posts, you need to be logged in.&lt;/li&gt;
&lt;li&gt;Here’s an example when you go to a secured API Route without a JWT Token (aka, you haven’t logged in):&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AOft6XR83WafE79nMBVEjUA.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AOft6XR83WafE79nMBVEjUA.png" alt="https://cdn-images-1.medium.com/max/800/1*Oft6XR83WafE79nMBVEjUA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example with no JWT attached to the API&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Authorization with Passport JWT&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Add these highlights to your &lt;code&gt;user.controller.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;express&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;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwt&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;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;passport&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;passport&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;validationResult&lt;/span&gt; &lt;span class="p"&gt;}&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;express-validator&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="cm"&gt;/**
 * GET/
 * retrieve and display all Users in the User Model
 */&lt;/span&gt;
&lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nx"&gt;passport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwt&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="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&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;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;userController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, test the API with Postman. Click on “Authorization”, and choose type “Bearer Token.” Then, paste your token in the token field and run:&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2Ay5u1ccu31puCLog8TPeOug.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2Ay5u1ccu31puCLog8TPeOug.png" alt="https://cdn-images-1.medium.com/max/800/1*y5u1ccu31puCLog8TPeOug.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With JWT, you’ll be able to retrieve all the users&lt;/p&gt;




&lt;h1&gt;
  
  
  Well Done!
&lt;/h1&gt;

&lt;p&gt;You’re now able to authorize and secure all other routes that require the user to login before using the API.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;Follow-up &amp;amp; connect with me on &lt;a href="https://github.com/calvinqc" rel="noopener noreferrer"&gt;Github&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/calvinqc/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; | &lt;a href="https://twitter.com/calvinqc_" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>security</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Quick Java, Spring, Kafka &amp; Zookeeper Setup on macOS</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Sat, 22 Aug 2020 20:18:14 +0000</pubDate>
      <link>https://dev.to/calvinqc/quick-java-spring-kafka-zookeeper-setup-on-macos-3e8</link>
      <guid>https://dev.to/calvinqc/quick-java-spring-kafka-zookeeper-setup-on-macos-3e8</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2A-CvUZ6GRTWQ_KZ0x.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2A-CvUZ6GRTWQ_KZ0x.jpg" alt="https://cdn-images-1.medium.com/max/1600/0*-CvUZ6GRTWQ_KZ0x.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image source from Cloudkarafka&lt;/p&gt;

&lt;h4&gt;
  
  
  In this tutorial/lab, you will experience a very simple and quick hands-on experience with:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;Springboot&lt;/li&gt;
&lt;li&gt;Apache Kafka &lt;/li&gt;
&lt;li&gt;Zookeeper&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Requirements&lt;/strong&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Testing with &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;. To learn more, you can watch this &lt;a href="https://www.youtube.com/watch?v=t5n07Ybz7yI&amp;amp;feature=emb_logo" rel="noopener noreferrer"&gt;video&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=udnX21__SuU" rel="noopener noreferrer"&gt;Understanding the core concept of Kafka&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Installment&lt;/strong&gt;
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Java 8&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ brew tap adoptopenjdk/openjdk
$ brew cask install adoptopenjdk8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Kafka&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ brew install kafka
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open the 1st terminal to start Zookeeper&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ zookeeper-server-start /usr/local/etc/kafka/zookeeper.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open the 2nd terminal&lt;/strong&gt; to start Kafka
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kafka-server-start /usr/local/etc/kafka/server.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open the 3rd terminal to create a Kafka topic&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kafka-topics --bootstrap-server localhost:9092 --topic &amp;lt;enter-a-topic&amp;gt; --create --partitions 1 --replication-factor 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  &lt;strong&gt;Create a Maven project with Springboot&lt;/strong&gt;
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;start.spring.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Spring Web&lt;/strong&gt; &amp;amp; &lt;strong&gt;Spring for Apache Kafka&lt;/strong&gt; dependencies
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AXvNJ-Qs8SqCMqS0QBXgBaA.png" alt="https://cdn-images-1.medium.com/max/1600/1*XvNJ-Qs8SqCMqS0QBXgBaA.png"&gt;
&lt;/li&gt;
&lt;li&gt;Open your project in IDE (I prefer to use IntelliJ)&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Configure Kafka Producer and Consumer
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Add this to &lt;code&gt;application.properties&lt;/code&gt; in &lt;code&gt;src/main/resources&lt;/code&gt; folder, and modify the highlights:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.datasource.url=jdbc:mysql://localhost:3306/&amp;lt;your-db-name&amp;gt;?allowPublicKeyRetrieval=true&amp;amp;useSSL=false&amp;amp;serverTimezone=UTC
spring.datasource.username=&amp;lt;your-db-username&amp;gt;
spring.datasource.password=&amp;lt;your-db-password&amp;gt;

app.topic=&amp;lt;same-topic-created-in-terminal&amp;gt;

spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.groupId=&amp;lt;any-group-id&amp;gt;

spring.kafka.consumer.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=&amp;lt;any-group-id&amp;gt;
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer

spring.kafka.producer.bootstrap-servers=localhost:9092
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Open a new terminal, and create a topic:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kafka-topics --bootstrap-server localhost:9092 --topic &amp;lt;same-topic-in-application.properties&amp;gt; --create --partitions 1 --replication-factor 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;Initialize Kafka Producer &amp;amp; Receiver Service&lt;/strong&gt;
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Inside the package &lt;code&gt;com.example&lt;/code&gt;, create these folders: &lt;code&gt;$ mkdir controller model repository service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create Producer and Receiver Services: &lt;code&gt;$ touch service/KafkaConsumer.java service/KafkaProducer.java&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add this to KafkaConsumer:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;enter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nn"&gt;here&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.kafka.annotation.KafkaListener&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;same-topic-in-resources&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;groupId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;same-group-id&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@KafkaListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;groupId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;groupId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add this code to KafkaProducer:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;enter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nn"&gt;here&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Autowired&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.kafka.core.KafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;KafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;kafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${app.topic}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;kafkaTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;Create Kafka API&lt;/strong&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Create a Kafka controller file: &lt;code&gt;$ touch controller/kafkaController.java&lt;/code&gt; and add this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;server.controller&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;server.service.KafkaConsumer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;server.service.KafkaProducer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Autowired&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/send"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;produce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/receive"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt; &lt;span class="nf"&gt;getConsumer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt; &lt;span class="nf"&gt;getProducer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setConsumer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setProducer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KafkaProducer&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;producer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;NOTE: There are also models and repository, which you use to configure with your database, but we don’t need it in this tutorial.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Final Project Structure
&lt;/h1&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AFZgx3Rg62Xw4UE5-YlVZSg.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AFZgx3Rg62Xw4UE5-YlVZSg.png" alt="https://cdn-images-1.medium.com/max/1600/1*FZgx3Rg62Xw4UE5-YlVZSg.png"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;Testing&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;There are 2 ways to send the message from the producer: Postman &amp;amp; Terminal.&lt;/p&gt;

&lt;p&gt;Open the 3rd terminal that you used to create the topic earlier&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kafka-console-consumer --bootstrap-server localhost:9092 --topic &amp;lt;enter-your-topic&amp;gt; --from-beginning
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1. Postman&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;POST/&lt;/strong&gt; method and enter &lt;strong&gt;localhost:8080/send&lt;/strong&gt; with the JSON body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "message": "Hello from Postman"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Terminal&lt;/strong&gt;&lt;br&gt;
Open the &lt;strong&gt;4th terminal,&lt;/strong&gt; and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kafka-console-producer --broker-list localhost:9092 --topic &amp;lt;enter-your-topic&amp;gt;
&amp;gt; Hello from the terminal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the terminal, you will see the message that you sent via postman and terminal &lt;strong&gt;in real-time.&lt;/strong&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%2Fcdn-images-1.medium.com%2Fmax%2F2400%2F1%2A3T6hwyuejLCpiF6rtLWsAg.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%2Fcdn-images-1.medium.com%2Fmax%2F2400%2F1%2A3T6hwyuejLCpiF6rtLWsAg.png" alt="https://cdn-images-1.medium.com/max/2400/1*3T6hwyuejLCpiF6rtLWsAg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Done &amp;amp; Congratulations!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Follow-up &amp;amp; connect with me on &lt;a href="https://github.com/calvinqc" rel="noopener noreferrer"&gt;Github&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/calvinqc/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; | &lt;a href="https://twitter.com/calvinqc_" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>java</category>
      <category>kafka</category>
      <category>webdev</category>
    </item>
    <item>
      <title>18 VS Code Extensions for a happier coding</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Thu, 20 Aug 2020 21:09:59 +0000</pubDate>
      <link>https://dev.to/calvinqc/18-vs-code-extensions-for-a-happier-coding-djc</link>
      <guid>https://dev.to/calvinqc/18-vs-code-extensions-for-a-happier-coding-djc</guid>
      <description>&lt;ol&gt;
&lt;li&gt;&lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag"&gt;AutoClose Tag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag"&gt;Auto Rename Tag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments"&gt;Better Comments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome"&gt;Debugger for Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint"&gt;ESLint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens"&gt;Gittens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/languages/go"&gt;Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=abusaidm.html-snippets"&gt;HTML Snippets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets"&gt;Javascript (ES6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets"&gt;code snippets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/languages/python"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ChakrounAnas.turbo-console-log"&gt;Turbo Console.log&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv"&gt;dotENV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense"&gt;npm Intellisense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense"&gt;Path Intellisense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer"&gt;Live Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight"&gt;Color Highlight&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What are Best Chrome Extensions for Web Dev and Cash-back?</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Thu, 20 Aug 2020 18:16:47 +0000</pubDate>
      <link>https://dev.to/calvinqc/best-chrome-extensions-for-web-dev-and-cash-back-19bj</link>
      <guid>https://dev.to/calvinqc/best-chrome-extensions-for-web-dev-and-cash-back-19bj</guid>
      <description>&lt;h2&gt;
  
  
  Here are the Top 6 that I used daily:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Are there any cool chrome extensions out there that could improve my web dev programming?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://adblockplus.org/"&gt;Adblock Plus&lt;/a&gt;: Block all the ads&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.grammarly.com/"&gt;Grammarly&lt;/a&gt;: Used to check my grammar when I write essays, blogs, etc.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.joinhoney.com/"&gt;Honey&lt;/a&gt;: To find me the best deals&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/rakuten-get-cash-back-for/chhjbpecpncaggjpdakmflnfcopglcmi?hl=en-US"&gt;Rakuten&lt;/a&gt;: Give me cash back when I shop online&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en"&gt;Redux Dev Tool&lt;/a&gt;: For debugging with React&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc?hl=en"&gt;JSON View&lt;/a&gt;: View JSON on the web browser prettier&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>webpack</category>
      <category>beginners</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Apps to install when you got the new Mac</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Thu, 20 Aug 2020 18:11:35 +0000</pubDate>
      <link>https://dev.to/calvinqc/2020-mac-setup-that-makes-your-life-easier-pg2</link>
      <guid>https://dev.to/calvinqc/2020-mac-setup-that-makes-your-life-easier-pg2</guid>
      <description>&lt;h4&gt;
  
  
  A guide to set up your Mac and improve your programming experience to another level with Vim/Zsh/Tmux, macOS Apps, Extensions for high productive development
&lt;/h4&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Inspiration&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Whenever I got a new laptop, it usually takes me up to 2 hours to re-setup everything again, and I start getting tired and annoyed. Every time I set up my Mac again, I learned something new and cool things that improve my programming experience better.&lt;/p&gt;

&lt;p&gt;So, I make a collection of setup and apps to share with you my personal guide of setting up a new Mac for software development.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;1. System Preferences&lt;/strong&gt;
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flfnqrhwf0v72r8y95sld.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flfnqrhwf0v72r8y95sld.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System Preferences &amp;gt; &lt;strong&gt;Trackpad/Keyboard&lt;/strong&gt; &amp;gt; set up as above images&lt;/li&gt;
&lt;li&gt;iCloud &amp;gt; login to your account&lt;/li&gt;
&lt;li&gt;Filevault: On&lt;/li&gt;
&lt;li&gt;Disable Ask Siri&lt;/li&gt;
&lt;li&gt;Location Services: On (Limited)&lt;/li&gt;
&lt;li&gt;Check software updates&lt;/li&gt;
&lt;li&gt;Messages app &amp;gt; add your Number + email&lt;/li&gt;
&lt;li&gt;App Store &amp;gt; install previously installed applications&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;2. Terminal&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.alfredapp.com/" rel="noopener noreferrer"&gt;Alfred&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It’s a replacement to Spotlight because it’s way much faster when it comes to search any files: &lt;code&gt;brew cask install alfred&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Brew&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install Xcode: &lt;code&gt;$ xcode-select --install&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install Homebrew: &lt;code&gt;$ /bin/bash -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;brew cask install&lt;/code&gt; to install an application&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.iterm2.com/" rel="noopener noreferrer"&gt;iTerm2&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A replacement to Terminal&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/u/792c2e6bc791" rel="noopener noreferrer"&gt;Clovis&lt;/a&gt; wrote an &lt;a href="https://medium.com/@Clovis_app/configuration-of-a-beautiful-efficient-terminal-and-prompt-on-osx-in-7-minutes-827c29391961" rel="noopener noreferrer"&gt;awesome tutorial&lt;/a&gt; on how to set up more in-depth&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;a href="https://www.slant.co/versus/1713/1715/~iterm2_vs_terminal-app" rel="noopener noreferrer"&gt;comparison&lt;/a&gt;: iTerm2 vs. Terminal&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: &lt;code&gt;brew cask install iterm2&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optional: &lt;strong&gt;&lt;a href="https://github.com/skwp/dotfiles" rel="noopener noreferrer"&gt;ZSH/Tmux/Vim&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AY7MmBIs_8Xfx76MQOSfbiA.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AY7MmBIs_8Xfx76MQOSfbiA.png" alt="https://cdn-images-1.medium.com/max/800/1*Y7MmBIs_8Xfx76MQOSfbiA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I used this &lt;a href="https://github.com/skwp/dotfiles" rel="noopener noreferrer"&gt;awesome guy’s repo&lt;/a&gt; as a template&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Git&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Git has become one of the main tools that every developer should know how to use it. The new Mac usually comes with Git pre-installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install git:&lt;/strong&gt; &lt;code&gt;brew install git&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Config git:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git config --global user.name "Your Name"
$ git config --global user.email "you@your-domain.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will constantly be using Git daily, and SSH will allow you to pull and push to git without re-entering email and password every single time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git already had an article on how to &lt;a href="https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;add SSH to your Mac&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. Install Mac Apps with command line&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you’re a fan of command-line, and you don’t want to install apps by going through each of them on Chrome. then you should try &lt;strong&gt;&lt;code&gt;mas&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install mas for quick setup: &lt;code&gt;$ brew install mas&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search for your app: &lt;code&gt;$ mas search XCode&lt;/code&gt; . You will find the app ID for each app&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the App ID into 1 command line: &lt;code&gt;$ mas install &amp;lt;app_id1&amp;gt; &amp;lt;app_id1&amp;gt; &amp;lt;app_id3&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If these apps below don’t have an app ID, then you have to install it from the browser. (Links included)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Work
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;XCode: 497799835&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://theunarchiver.com/" rel="noopener noreferrer"&gt;The Unarchiver:&lt;/a&gt; 425424353&lt;/li&gt;
&lt;li&gt;Microsoft Word: 462054704&lt;/li&gt;
&lt;li&gt;Excel: 462058435&lt;/li&gt;
&lt;li&gt;PowerPoint: 462062816&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Communication
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://slack.com/" rel="noopener noreferrer"&gt;Slack:&lt;/a&gt; 803453959&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.notion.so/" rel="noopener noreferrer"&gt;Notions&lt;/a&gt;: 974929595&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zoom.us/" rel="noopener noreferrer"&gt;Zoom:&lt;/a&gt; 884018914&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Entertainment
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://apps.apple.com/us/app/messenger/id454638411" rel="noopener noreferrer"&gt;Messenger&lt;/a&gt;: 1480068668&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.wechat.com/en/" rel="noopener noreferrer"&gt;WeChat&lt;/a&gt;: 836500024&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://line.me/en/" rel="noopener noreferrer"&gt;Line:&lt;/a&gt; 539883307&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.google.com/chrome/?brand=CHBD&amp;amp;gclid=Cj0KCQjwo6D4BRDgARIsAA6uN1_SszdlH-F-7Lu13jLzZIj8BAfWsSBL5M0zhXeS677r88nwsF0uHrwaAt5GEALw_wcB&amp;amp;gclsrc=aw.ds" rel="noopener noreferrer"&gt;Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.viber.com/en/" rel="noopener noreferrer"&gt;Viber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.spotify.com/us/download/other/" rel="noopener noreferrer"&gt;Spotify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://open.spotify.com/" rel="noopener noreferrer"&gt;Open Spotify:&lt;/a&gt; This website lets you listen to Spotify music with &lt;strong&gt;NO Ads&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;5. Chrome Extension&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You don’t want to install many Chrome extensions unless you want it to &lt;em&gt;“eat”&lt;/em&gt; a lot of your RAM or unless you have a powerful computer.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Here are the TOP 6 that I used daily:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://adblockplus.org/" rel="noopener noreferrer"&gt;Adblock Plus&lt;/a&gt;: Block all the ads&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.grammarly.com/" rel="noopener noreferrer"&gt;Grammarly&lt;/a&gt;: Used to check my grammar when I write essays, blogs, etc.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.joinhoney.com/" rel="noopener noreferrer"&gt;Honey&lt;/a&gt;: To find me the best deals&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/rakuten-get-cash-back-for/chhjbpecpncaggjpdakmflnfcopglcmi?hl=en-US" rel="noopener noreferrer"&gt;Rakuten&lt;/a&gt;: Give me cash back when I shop online&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en" rel="noopener noreferrer"&gt;Redux Dev Tool&lt;/a&gt;: For debugging with React&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc?hl=en" rel="noopener noreferrer"&gt;JSON View&lt;/a&gt;: View JSON on the web browser prettier&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;6. VSCode Extension&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag" rel="noopener noreferrer"&gt;AutoClose Tag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag" rel="noopener noreferrer"&gt;Auto Rename Tag&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments" rel="noopener noreferrer"&gt;Better Comments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome" rel="noopener noreferrer"&gt;Debugger for Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens" rel="noopener noreferrer"&gt;Gittens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/languages/go" rel="noopener noreferrer"&gt;Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=abusaidm.html-snippets" rel="noopener noreferrer"&gt;HTML Snippets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets" rel="noopener noreferrer"&gt;Javascript (ES6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets" rel="noopener noreferrer"&gt;code snippets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/languages/python" rel="noopener noreferrer"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ChakrounAnas.turbo-console-log" rel="noopener noreferrer"&gt;Turbo Console.log&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv" rel="noopener noreferrer"&gt;dotENV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense" rel="noopener noreferrer"&gt;npm Intellisense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense" rel="noopener noreferrer"&gt;Path Intellisense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer" rel="noopener noreferrer"&gt;Live Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight" rel="noopener noreferrer"&gt;Color Highlight&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>beginners</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to keep your Intro short, unique, and creative at the same time</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Wed, 19 Aug 2020 18:35:47 +0000</pubDate>
      <link>https://dev.to/calvinqc/my-creative-way-of-readme-intro-10an</link>
      <guid>https://dev.to/calvinqc/my-creative-way-of-readme-intro-10an</guid>
      <description>&lt;p&gt;👉 &lt;a href="http://github.com/calvinqc" rel="noopener noreferrer"&gt;http://github.com/calvinqc&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa05pqr9u0ch0agjov4h0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa05pqr9u0ch0agjov4h0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Feel free to share yours in the comment!&lt;/p&gt;

</description>
      <category>github</category>
      <category>showdev</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Do less and get more jobs done with 5 WFH alternative apps</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Wed, 19 Aug 2020 05:14:05 +0000</pubDate>
      <link>https://dev.to/calvinqc/do-less-and-get-more-jobs-done-with-5-wfh-alternative-apps-2d3e</link>
      <guid>https://dev.to/calvinqc/do-less-and-get-more-jobs-done-with-5-wfh-alternative-apps-2d3e</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O3vyKBRk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AwkXWOINpI4rDoDys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O3vyKBRk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AwkXWOINpI4rDoDys.png" alt="https://cdn-images-1.medium.com/max/1600/0*wkXWOINpI4rDoDys.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the COVID-19, everything shifted to move online. I start using Apple’s default apps such as Photos, &lt;a href="https://www.guidingtech.com/top-apple-mail-alternatives-iphone/"&gt;Mail&lt;/a&gt;, Calendar, &lt;a href="https://www.guidingtech.com/apple-reminders-alternatives-ios/"&gt;Reminders&lt;/a&gt;, Notes,... which are all simple, lightweight, clean, and do the work I need. &lt;/p&gt;

&lt;p&gt;Then, as I’ve learned, I found more alternative apps that do the job better than Apple, which are &lt;em&gt;faster, and nice UI, and has more features&lt;/em&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;1. &lt;a href="https://sparkmailapp.com/"&gt;Spark Mail App&lt;/a&gt;&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GEGXFaVq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2Aota3PM0ZAnF8zqHYvA9EaA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GEGXFaVq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2Aota3PM0ZAnF8zqHYvA9EaA.png" alt="https://cdn-images-1.medium.com/max/2400/1*ota3PM0ZAnF8zqHYvA9EaA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Templates&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; When I was sending out an email to different clients with the same template, I had to &lt;em&gt;copy and paste multiple times&lt;/em&gt; and make changes. Sometimes I forgot to change the name of the person, and I felt so &lt;em&gt;embarrassed&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Or maybe I might lose the clipboard and had to search for the email I sent, and copy the template again, which was quite inconvenient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; With Spark, I can freely create different templates for every scenario, and Of course I can share the template with my team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GHBt4hPT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2A9ZOMu3GJBO7pYIoeKnGMtg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GHBt4hPT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2A9ZOMu3GJBO7pYIoeKnGMtg.png" alt="https://cdn-images-1.medium.com/max/1200/1*9ZOMu3GJBO7pYIoeKnGMtg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Send later&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I can send an email in the early morning but &lt;em&gt;don’t want to wake up at 7 am&lt;/em&gt; and send the email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mDHAGiXW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2ApQlnIfA0AOeA1xQiB135Bg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mDHAGiXW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2ApQlnIfA0AOeA1xQiB135Bg.png" alt="https://cdn-images-1.medium.com/max/1600/1*pQlnIfA0AOeA1xQiB135Bg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know that there are other 3rd parties software that can schedule an email, but having ones built-in the Mail App makes everything &lt;em&gt;easier&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Synchronization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When I changed a new laptop, I have to enter all 5–6 emails again. With Spark, all I need is one email, and it will automatically sync all emails into my device.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Smart Inbox &amp;amp; Search&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pmQacXAI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2AFaUwVVoPWL_h9E9Wo2Sa3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pmQacXAI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2AFaUwVVoPWL_h9E9Wo2Sa3A.png" alt="https://cdn-images-1.medium.com/max/1200/1*FaUwVVoPWL_h9E9Wo2Sa3A.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Apple Mail, when I pinned an email, it lost among many new emails after a few minutes. If I have different types of pins, I would have to go to "Pinned" and search for it. And usually, Apple Mail search drives me nut.&lt;/p&gt;

&lt;p&gt;With Spark, the "Pinned" is separated from the rest of regular emails so I could see it on the top of my mailing list.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Spark for Team&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The real-time online collaboration will be the main focus of 2020, and Readdle is creating the future of email with Spark.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But you’ll need to pay to use it with Team&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WyzaU_3K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A1TxMtf9I9x77w8suIJz2XQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WyzaU_3K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A1TxMtf9I9x77w8suIJz2XQ.png" alt="https://cdn-images-1.medium.com/max/1600/1*1TxMtf9I9x77w8suIJz2XQ.png"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;2. &lt;a href="https://flexibits.com/fantastical"&gt;Fantastical Calendar&lt;/a&gt;&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8CuJEcQT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AHV7E45Uuu_1V7yladfyLsA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8CuJEcQT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AHV7E45Uuu_1V7yladfyLsA.png" alt="https://cdn-images-1.medium.com/max/1600/1*HV7E45Uuu_1V7yladfyLsA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;User Interface&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It’s 2020, and to be honest, people would likely try the app because it’s &lt;strong&gt;PRETTY!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fantastical has a brand new user interface with multiple views, including detailed (and beautiful) full-screen views for iPhone, iPad, and Mac.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YHmPa9-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2Aq_PzIPT7XfX5g7lozU6KdA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YHmPa9-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2Aq_PzIPT7XfX5g7lozU6KdA.png" alt="https://cdn-images-1.medium.com/max/1200/1*q_PzIPT7XfX5g7lozU6KdA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--379J0vXZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2APmyjr_mzYq9AQtVJ4nLJUA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--379J0vXZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2APmyjr_mzYq9AQtVJ4nLJUA.png" alt="https://cdn-images-1.medium.com/max/1200/1*Pmyjr_mzYq9AQtVJ4nLJUA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, it uses a mixture of a white &amp;amp; dark theme, which looks amazing&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conference Calls&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This feature is simple, but I think I use it more than anything else when it comes to online meetings these days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7ovMraA3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AXNa73CflJ55Y-E9CVLrUKQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7ovMraA3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AXNa73CflJ55Y-E9CVLrUKQ.png" alt="https://cdn-images-1.medium.com/max/1600/1*XNa73CflJ55Y-E9CVLrUKQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can create an event with a Conference Calls link such as Zoom, Google Meet, etc. without going to a 3rd party or different apps such as Calendly or Google Calendar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt; It also has a Join icon in the menu bar.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Different Calendar Sets&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Calendar sets let me group and view different sets of calendars, include from my team, my family, and all calendar together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PwXRhTkf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AeyKexiNMoXl9K1NyrGmM8g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PwXRhTkf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AeyKexiNMoXl9K1NyrGmM8g.gif" alt="https://cdn-images-1.medium.com/max/1600/1*eyKexiNMoXl9K1NyrGmM8g.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This features completely removes any distractions during my normal time, so I don’t need to worry, or startled:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Oh shoot, I have another meeting. Oh never mind, it’s my girlfriend’s meeting.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Customization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SDg4byfX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2AqVFFqB4TzcD68Q-ERHDD3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SDg4byfX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2AqVFFqB4TzcD68Q-ERHDD3g.png" alt="https://cdn-images-1.medium.com/max/1200/1*qVFFqB4TzcD68Q-ERHDD3g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Template:&lt;/strong&gt; Yes, similar to Spark, it has a template so you can create different events without finding the exact events over 3 months ago.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shortcut:&lt;/strong&gt; It becomes much easier to see what’s happening today, and create a new event with just 1 steps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom color:&lt;/strong&gt; I can choose all meetings in different colors without creating a new calendar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time Zone:&lt;/strong&gt; I could different timezones to make sure that it does not conflict with other schedules from New York or Vietnam.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Pricing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Of course, one of the major reasons that I was doubtful, in the beginning, was &lt;strong&gt;&lt;a href="https://flexibits.com/fantastical/pricing"&gt;SUBSCRIPTION&lt;/a&gt;.&lt;/strong&gt; But after 2 weeks, I don’t want to go back to Apple Calendar.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;3. &lt;a href="https://www.alfredapp.com/"&gt;Alfred4&lt;/a&gt;&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;I used the spotlight for years, but when I want to search for a quick file, a folder, or a photo. It fails and disappoints me. I had to go back to the Finder and look for it.&lt;/p&gt;

&lt;p&gt;But Alfred is different and has more cool features than you could do with just a search Spotlight. There’s only 1 word I can describe it: &lt;strong&gt;SUPER-FAST!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.alfredapp.com/help/features/default-results/"&gt;Default Results&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WW8BzKTc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AF5IXvlVhBfVbmxKUga15Gg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WW8BzKTc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AF5IXvlVhBfVbmxKUga15Gg.png" alt="https://cdn-images-1.medium.com/max/1600/1*F5IXvlVhBfVbmxKUga15Gg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.alfredapp.com/help/features/file-search/"&gt;File Search&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Using the file search keywords is the best way to find files; it keeps the default results both fast and focused&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yovlAVRt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2Acx8sE1ACLreed1CdzeKahg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yovlAVRt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2Acx8sE1ACLreed1CdzeKahg.png" alt="https://cdn-images-1.medium.com/max/2400/1*cx8sE1ACLreed1CdzeKahg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.alfredapp.com/help/features/web-search/"&gt;Web Search&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Search the web using the built-in default web searches or create your own custom searches&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6PBBdYDf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AdWhVtJqlsErpkMRbzT4tFg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6PBBdYDf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AdWhVtJqlsErpkMRbzT4tFg.png" alt="https://cdn-images-1.medium.com/max/1600/1*dWhVtJqlsErpkMRbzT4tFg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.alfredapp.com/help/features/clipboard/"&gt;Clipboard History&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Automatically store copied items in a searchable clipboard history&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h7PxE0x4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AKbZzPnZZvC3Q_POyujipFQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h7PxE0x4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AKbZzPnZZvC3Q_POyujipFQ.png" alt="https://cdn-images-1.medium.com/max/1600/1*KbZzPnZZvC3Q_POyujipFQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.alfredapp.com/help/features/calculator/"&gt;Calculator&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Do quick mathematical calculations and copy the result to the macOS clipboard&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EAs1voGq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AClCAJAo4q0ZphwbBl7B38Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EAs1voGq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AClCAJAo4q0ZphwbBl7B38Q.png" alt="https://cdn-images-1.medium.com/max/1600/1*ClCAJAo4q0ZphwbBl7B38Q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.alfredapp.com/help/features/terminal/"&gt;Terminal/Shell&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sclm5nOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AsbC_8hfFrYh0hoX-3yJVCA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sclm5nOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AsbC_8hfFrYh0hoX-3yJVCA.png" alt="https://cdn-images-1.medium.com/max/1600/1*sbC_8hfFrYh0hoX-3yJVCA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quickly open the terminal and run shell commands&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yWy93pSc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2AS8fx-nD0Uxaz8beanymKcA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yWy93pSc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2AS8fx-nD0Uxaz8beanymKcA.png" alt="https://cdn-images-1.medium.com/max/2400/1*S8fx-nD0Uxaz8beanymKcA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You could find more features &lt;a href="https://www.alfredapp.com/help/overview/"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;4. &lt;a href="https://www.notion.so/"&gt;Notion&lt;/a&gt;&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nV6jfKdf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AGdWAFpYdnM-Ee44zVS7hyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nV6jfKdf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AGdWAFpYdnM-Ee44zVS7hyg.png" alt="https://cdn-images-1.medium.com/max/1600/1*GdWAFpYdnM-Ee44zVS7hyg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.notion.so/"&gt;Notion&lt;/a&gt;&lt;/strong&gt; is an &lt;strong&gt;all-in-one workspace&lt;/strong&gt; where you can write, plan, collaborate, and get folders organized. It allows you to take notes, add tasks, manage projects with Teams.&lt;/p&gt;

&lt;p&gt;Before the COVID, Notion has a paid plan if you run out of storage, or if you add more people into the workspace.&lt;/p&gt;

&lt;p&gt;During the COVID, it has made &lt;strong&gt;FREE for all.&lt;/strong&gt; And only charge when you use it with Team.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;strong&gt;5. &lt;a href="https://iterm2.com/"&gt;iTerm2&lt;/a&gt; (Terminal)&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;If you’re a developer, you don’t want to miss trying this awesome replacement for the terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Customizable&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dvF3QwGO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AChqMCrMlLBw3tXOW" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dvF3QwGO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AChqMCrMlLBw3tXOW" alt="https://cdn-images-1.medium.com/max/1600/0*ChqMCrMlLBw3tXOW"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iTerm2 also lets you customize the color scheme, font, transparency, etc.&lt;/li&gt;
&lt;li&gt;It’s possible to choose a font and adjust vertical and horizontal spacing.&lt;/li&gt;
&lt;li&gt;Any key can be mapped to any function&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Autocomplete &amp;amp; History are built-in&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Ignore the Uppercase&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;iTerm2 can store up to 4M of the history of commands you already used.&lt;/li&gt;
&lt;li&gt;This allows for better search and makes it possible to type the few first letter command only once and then search for it through the history for subsequent uses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Integration with other Dev Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The great mouse and clipboard support that are built-in go really well with &lt;strong&gt;tmux&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Works perfectly with &lt;strong&gt;Oh My Zsh.&lt;/strong&gt; It’s a perfect base to add &lt;a href="https://ohmyz.sh/"&gt;Oh My Zsh&lt;/a&gt; on top of it and enjoy a lot of themes and a really pleasant look and feel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more features, click &lt;a href="https://iterm2.com/features.html"&gt;here&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;That’s all 5 alternative apps I personally use in my daily life to boost my working performance! &lt;/p&gt;

&lt;p&gt;Let me know if you found any interesting apps&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>technology</category>
      <category>beginners</category>
      <category>news</category>
    </item>
    <item>
      <title>What Does it Take to Build a Successful, Cross-Functional Team?</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Tue, 21 Jul 2020 05:47:48 +0000</pubDate>
      <link>https://dev.to/calvinqc/what-does-it-take-to-build-a-successful-cross-functional-team-1f0b</link>
      <guid>https://dev.to/calvinqc/what-does-it-take-to-build-a-successful-cross-functional-team-1f0b</guid>
      <description>&lt;p&gt;When one project or organization gets bigger and involves more collaborations between different people from different expertise, it‘s imperative to ensure smooth integration among different teams.&lt;/p&gt;

&lt;p&gt;Therefore, understanding the characteristic of cross-functional cooperation (CFC) has become one of the basic knowledge of any manager.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Cross-functional Cooperation (CFC)?
&lt;/h1&gt;

&lt;p&gt;Cross-functional cooperation is a group of people including those with different expertise in finance, operations, marketing, HR, and IT to work together towards a common goal. Each will focus on their area but share knowledge and resources to facilitate and expedite the successful team goal.&lt;/p&gt;

&lt;h1&gt;
  
  
  Managers need to clearly understand what defines a successful CFC
&lt;/h1&gt;

&lt;p&gt;When individuals with diverse work styles and functions come together the results can be innovative and transformative. Research shows however that despite its positive effects, many cross-functional teams are dysfunctional.&lt;/p&gt;

&lt;p&gt;Therefore, it is important that leaders or managers must have a clear understanding of what influencers will impact the team’s productivity and its possible outcomes if they could achieve those.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Influencers
&lt;/h1&gt;

&lt;p&gt;There are 4 main influencers that impact cooperation&lt;br&gt;
Image for post&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VCHsTR61--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7mop9weh7ssbnoiamv5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VCHsTR61--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7mop9weh7ssbnoiamv5z.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  A superordinate goal
&lt;/h1&gt;

&lt;p&gt;To complete a major goal of the project, managers usually split into many small features/projects with a clear goal, which will support one final big project.&lt;/p&gt;

&lt;p&gt;In order to build a beautiful and well functional Macbook, we cannot have 1 team to build everything.&lt;/p&gt;

&lt;p&gt;Therefore, it is split into many small teams to work on specific tasks, which support one feature of the Macbook.&lt;/p&gt;

&lt;p&gt;For example, we may have 2 teams: Software and Hardware.&lt;br&gt;
The software Team can split into many sub-teams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloud, iOS Version, UI/UX…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same thing for the Hardware team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Battery, Trackpad, Mainboard, Wifi, Bluetooth…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, those listed teams above can be divided into many smaller teams to work on smaller parts to support that feature. In the final phase, all small features combine together to create a successful Macbook Pro as we see today.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rules and procedures
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;No team is successful without rules/regulations&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When we code as a team, there is a specific rule or guideline for all developers to follow so that others can read the code easily and reduce the time to understand.&lt;/p&gt;

&lt;p&gt;If a team consist of 10 developers and all 10 developers have 10 different coding style, then we will have a massive merge conflict when other developers try to merge different features to make their feature works. It will waste a lot of time and headaches.&lt;/p&gt;

&lt;p&gt;3 months ago, I wrote 2 simple tips to increase code development, which now all my team members could code with more confidence than other teams in classes.&lt;/p&gt;

&lt;p&gt;Consequently, it is imperative that a clear hierarchy is defined and the rules of engagement and communication are understood by all.&lt;/p&gt;

&lt;h1&gt;
  
  
  Physical proximity
&lt;/h1&gt;

&lt;p&gt;For a team to produce the best results, it’s better for everyone to stay close to each other.&lt;/p&gt;

&lt;p&gt;When I intern at PayPal, all the team members sit together on the same floor, the same area. So whenever my manager wants to do a standup meeting, everyone can walk 5 seconds to his desk. Or if I have questions, I can move my chair next to my mentor to ask questions. This will save a lot of time and provide better communication.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“When project team members work near one another, they are more likely to communicate and, ultimately, cooperate”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Due to Covid-19: Many companies now switch to remote meetings via Zoom, Facebook Messenger, Google Meet/Google Hangout, Discord, etc.&lt;/p&gt;

&lt;p&gt;I‘ve been a fan of Facebook Messenger and WebRTC technology, and now they just released new features to share screen and add more people to the group’s video call, which is so awesome.&lt;/p&gt;

&lt;h1&gt;
  
  
  Accessibility
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Having the same working environment system will enable everyone to collaborate with each other better.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When we want to schedule a meeting, team members should have the same calendar system such as Outlook, Google Calendar, Calendar. This allows everyone to easily see each others’ schedules and make a meeting without having back-to-back rescheduling’s conflicts.&lt;/p&gt;

&lt;p&gt;There are many great tools for project management such as MS Project, Asana, Monday, Sunsama, Smartsheet, etc. but since most of the tools are paid, so as a developer, I just prefer Github Project&lt;/p&gt;

&lt;h1&gt;
  
  
  Outcome
&lt;/h1&gt;

&lt;p&gt;At the end of a milestone, the project manager will analyze and evaluate the team’s performance based on 2 different outcomes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Task outcomes
First and foremost, managers will examine the success of a project by the final result:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Whether or not have the team achieved the goal this week or month.&lt;/li&gt;
&lt;li&gt;By giving the best resources to the team, have they fully or partially achieve the goal&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Psychosocial outcomes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This type of outcome usually results in the team’s communication, individuals’ emotion.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The emotional and psychological effects that strong performance will have on the project team.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Is everyone happy with each other?&lt;/li&gt;
&lt;li&gt;Is it easy for each member to express and listen to different ideas?
Then, the manager will learn what to improve for better results next time and continue to keep or change the way the team works!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>teamwork</category>
      <category>productivity</category>
      <category>management</category>
      <category>leadership</category>
    </item>
    <item>
      <title>WebRTC — The technology that powers Google Meet/Hangout, Facebook Messenger and Discord</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Mon, 20 Jul 2020 22:25:37 +0000</pubDate>
      <link>https://dev.to/calvinqc/webrtc-the-technology-that-powers-google-meet-hangout-facebook-messenger-and-discord-39d1</link>
      <guid>https://dev.to/calvinqc/webrtc-the-technology-that-powers-google-meet-hangout-facebook-messenger-and-discord-39d1</guid>
      <description>&lt;p&gt;Here is what happens during a P2P connection, and all you need to know about Web Real-Time Communication&lt;/p&gt;

&lt;p&gt;Read the original Post &lt;a href="https://medium.com/swlh/webrtc-the-technology-that-powers-google-meet-hangout-facebook-messenger-and-discord-cb926973d786"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Everything you need to know about Web RTC in 9 minutes&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  History of Real-time Communication
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Around the 2010s, real-time communication was only available using additional software, plugins, or Adobe Flash.&lt;/li&gt;
&lt;li&gt;In 2013, the first cross-browser video call between Chrome &amp;amp; Firefox was introduced.&lt;/li&gt;
&lt;li&gt;In 2014, the first cross-browser data transfer occurred, opening to a new-emerging trend in real-time communication via the client-side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today, it is known as the Web RTC that we use every day in Chrome, Mozilla Firefox, Opera, Safari, Edge, iOS, and Android.&lt;/p&gt;

&lt;p&gt;Source by CometChat&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;WebRTC stands for Web Real-Time Communication, which is a networking technology introduced in 2011 by Google to enable real-time audio, video, and data transmission across the web and native browsers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Its mission is to enable rich, high-quality RTC applications to be developed for the browser, mobile platforms, and IoT devices, and allow them all to communicate via a common set of protocols."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;WebRTC allows web apps to create Peer-To-Peer communication. WebRTC is a vast topic, so in this post, we'll focus on the following issues of WebRTC:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why do developers &amp;amp; companies love Web RTC?&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What happens during the P2P connection&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signaling&lt;/li&gt;
&lt;li&gt;NATs &amp;amp; ICE&lt;/li&gt;
&lt;li&gt;STUN &amp;amp; TURN Server&lt;/li&gt;
&lt;li&gt;VP9 Video Codec&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WebRTC APIs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  Why do developers &amp;amp; companies love Web RTC?
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Free open source&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It provides browsers with end-to-end direct communication and allows developers to facilitate this connection easily.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Speed Enhancement&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No longer needs to be routed through a server; it reduces latency and bandwidth consumption.&lt;/li&gt;
&lt;li&gt;Direct communication improves the speed of data transfer &amp;amp; file sharing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No third party app required&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requiring no additional software, plugins, or continuous server involvement (Well, it does, but only in the beginning, you will know why later)&lt;/li&gt;
&lt;li&gt;Easily be embedded in any websites and connect peers across the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Easy to implement&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less time and effort to facilitate peer-to-peer (P2P) connection.&lt;/li&gt;
&lt;li&gt;All the functionality can be done through the client-side.
Developers just need to download a WebRTC compatible browser and use&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compatible&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supported by most popular browsers: Microsoft Edge, Google Chrome, Mozilla Firefox, Safari, Safari, Opera, Vivaldi.&lt;/li&gt;
&lt;li&gt;Supported by Android, Chrome OS, Firefox OS, BlackBerry 10, iOS, Tizen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provide a safe connection across many browsers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encryption is mandatory for all of the WebRTC components.&lt;/li&gt;
&lt;li&gt;Since it is not a plugin, it runs inside the browser's sandbox without creating a new process so that no malware can get into the user's system.&lt;/li&gt;
&lt;li&gt;No need to keep track of the updates. With the automatic updates of the browser's version, the user gets the patch as soon as it is available.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  What happens during the P2P connection
&lt;/h1&gt;

&lt;p&gt;Image by PubNubTo connect two browsers, Web RTC is required to perform five steps to set up a P2P connection.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Signal processing to remove ambient noise from the audio or video.&lt;/li&gt;
&lt;li&gt;Codec handling to compress and decompress the audio or video.&lt;/li&gt;
&lt;li&gt;Routing from one peer to another through firewalls, (NATs), and relays to create an Interactive Connectivity Establishment (ICE)&lt;/li&gt;
&lt;li&gt;User data is encrypted before transmitting across connections.&lt;/li&gt;
&lt;li&gt;Managing bandwidth to the user what each peer has to give&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Signaling
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;P2P connections in the browser are established by a server to ensure all peers agree to the session.&lt;/li&gt;
&lt;li&gt;Information like session keys, error messages, media metadata, codecs, bandwidth, and public IP address and ports are shared between peers to create the connection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The server&lt;/strong&gt; signals to both peers to determine what media format to use and what each peer wants to send to the other.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h1&gt;
  
  
  Network Address Translations (NATs) and ICE
&lt;/h1&gt;

&lt;p&gt;NATs translate a private IP address found on devices like a home router to a public IP address. Firewalls and NATs slow the process by blocking specific protocols or ports. The solution WebRTC uses is a framework called ICE.&lt;br&gt;
ICE establishes a P2P connection over the internet by trying all connections in parallel and selecting the most efficient path. There are two types of connections: &lt;strong&gt;STUN &amp;amp; TURN&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  STUN Servers
&lt;/h1&gt;

&lt;p&gt;It first works connecting through a STUN (Session Traversal Utilities for NAT) server to get a direct link through the network address.&lt;/p&gt;

&lt;p&gt;A STUN server provides the requestor a public IP address to communicate with others. Its purpose is to help a requestor answer the question, "What's my IP Address?"&lt;/p&gt;

&lt;h2&gt;
  
  
  How STUN servers work
&lt;/h2&gt;

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

&lt;p&gt;To set up a connection with other peers, an endpoint is required to know its public IP to share with others.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When an endpoint (Calvin) is behind a NAT/Firewall, it can only identify its local IP address, and the other (Elana) cannot connect to the local IP because of the firewall security.&lt;/li&gt;
&lt;li&gt;This endpoint will ask for help from the STUN server to provide its public IP address and a type of NAT.&lt;/li&gt;
&lt;li&gt;The other endpoint (Elana) can attempt the connection between the two using the given public IP address from the STUN server.&lt;/li&gt;
&lt;li&gt;If successful, media will flow directly to each endpoint without a 3rd party or another server.&lt;/li&gt;
&lt;li&gt;For security, all STUN servers will be dropped and wait for the next query.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Limitations - Symmetric NAT
&lt;/h1&gt;

&lt;p&gt;However, the situation above may &lt;em&gt;sometimes fail&lt;/em&gt;, and the PORT and IP number will be changed.&lt;/p&gt;

&lt;p&gt;This situation is called "symmetric NAT" as the public IP address of the STUN server does not have enough capability to establish connectivity here, as the port would also need a translation.&lt;/p&gt;

&lt;p&gt;Some routers use Symmetric NAT, which is made to add another security layer to the endpoint or avoid many strangers to connect to your device. A Symmetric NAT not only translates the IP address from private to public but also translates ports.&lt;/p&gt;

&lt;p&gt;In other words, the router will only accept connections from known peers that the user previously connected to. Hence, another solution is made to ensure that the connection between two peers is successful is through the TURN server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why STUN servers are useful
&lt;/h1&gt;

&lt;p&gt;As a protocol, STUN is super fast, lightweight, and straightforward. It allows the media to travel directly to each other in a short time. STUN is beneficial to speed up the connection and get the result faster in real-time.&lt;/p&gt;

&lt;p&gt;The scenario is similar when the user is using LAN to download the data, which is faster than downloading from the Wi-fi. Most importantly, it allows the media to travel directly between both endpoints. STUN can be used publicly and free.&lt;/p&gt;

&lt;h1&gt;
  
  
  TURN Servers
&lt;/h1&gt;

&lt;p&gt;TURN (Traversal Using Relays around NAT) server acts as relay servers incase the peer-to-peer connection dies. While STUN servers are used to establish the connection, TURN servers remain active throughout the association.&lt;/p&gt;

&lt;p&gt;A TURN server keeps relaying the media between the WebRTC peers. That is why the term "relay" is used to define TURN.&lt;/p&gt;

&lt;h2&gt;
  
  
  How TURN servers work
&lt;/h2&gt;

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

&lt;p&gt;This relay server is used to relay traffic if the STUN server fails, and it also &lt;strong&gt;has the STUN's functions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The TURN server is a STUN server with transmitting capability built-in. More specifically, TURN is used to relay audio/video/data streaming between peers, not signaling data.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Follow the steps for STUN Servers&lt;/li&gt;
&lt;li&gt;If STUN fails, an end-user will create a connection with a TURN server, inform all peers to send data to the server, which is in charge of transferring data to the first end-user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One main reason why a STUN server is always used first is that the TURN server is too expensive, and uses massive bandwidth if HD Video is streamed online.&lt;/p&gt;

&lt;h1&gt;
  
  
  VP9 Video Codec
&lt;/h1&gt;

&lt;p&gt;One of the main features, why many people start to use WebRTC, is for video streaming. As live video becomes more mainstream and starts getting higher quality, it requires data transfer to be faster or the packet size to be smaller to be easily transferred.&lt;/p&gt;

&lt;p&gt;That is when VP9 Video Codec takes place to compress and decompress the audio or video. It helps stream video quicker and more apparent. By supporting VP8, Safari 12.1 can exchange live video with other peers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dd-SJSiR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aik6ikypshs5ojhj1cpt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dd-SJSiR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aik6ikypshs5ojhj1cpt.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VP9, which is an improvement from VP8, is a video compression format owned by Google and created by On2 Technologies.&lt;/p&gt;

&lt;p&gt;The main feature is to conceal packet loss and clean up noisy images, as well as capture and playback capabilities across multiple platforms.&lt;/p&gt;

&lt;p&gt;With VP9, users can use WebRTC to stream a 720p video without packet loss or delay. It can also support a 1080p video call at the same bandwidth and helps reduce poor connections and data usage to avoid expensive costs for users.&lt;/p&gt;




&lt;h1&gt;
  
  
  JavaScript APIs
&lt;/h1&gt;

&lt;p&gt;There are three main Javascript APIs that handle audio capturing, video conferencing, and data transmission:&lt;/p&gt;

&lt;h2&gt;
  
  
  MediaStream
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Utilizes a user's camera and microphone to capture and stream audio and video. Using this API allows you to get access to input devices such as the microphone and the web camera.&lt;/li&gt;
&lt;li&gt;When a developer integrates WebRTC into their website, they can create constraints on how they want the audio and video streamed. Limitations like the frame rate, size of the video frame, resolutions, and much more.&lt;/li&gt;
&lt;li&gt;This API was provided as part of HTML 5, whereas the other two APIs are explicitly offered for WebRTC.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  RTCPeerConnection
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Send the captured stream of audio and video in real-time across the internet to another WebRTC endpoint. Using these APIs enables users to transmit audio and video captured by getUserMedia to other peers.&lt;/li&gt;
&lt;li&gt;Has features to connect to a remote peer, maintain and monitor the connection, and close the connection once after it's done.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  RTCDataChannel
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Transmit arbitrary data. Each data channel is associated with an RTCPeerConnection.&lt;/li&gt;
&lt;li&gt;Built-in security (DTLS) and congestion control.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;p&gt;One of the security risks in any real-time communication application may raise during the transmission of data. Eventually, encryption is a mandatory feature of WebRTC and is enforced on all components.&lt;/p&gt;

&lt;p&gt;WebRTC uses two standardized encrypting protocols:&lt;/p&gt;

&lt;h2&gt;
  
  
  Datagram Transport Layer Security (DTLS)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A standardized protocol that is built in a browser. It's used to encrypt data streams. It is based on the Transport Layer Protocol (TLP).&lt;/li&gt;
&lt;li&gt;Preserves the semantics of the transport because DTLS uses User Data Protocol (UDP).&lt;/li&gt;
&lt;li&gt;It is an extension of Secure Sockets Layer (SSL); any SSL protocol could be used to secure WebRTC data allowing end-to-end encryption.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Secure Real-time Transport Protocol (SRTP)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Used to encrypt media streams.&lt;/li&gt;
&lt;li&gt;It is an extension to Real-Time Transport Protocol (RTP), which does not have any built-in security mechanisms.
Adds protection, integrity, and message authentication to the RTP.&lt;/li&gt;
&lt;li&gt;Downside: While it provides encryption for the RTP packets, it does not encrypt the header.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Steps to secure a link between 2 peers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Initiates the signaling process exchanges the metadata between two peers.&lt;/li&gt;
&lt;li&gt;ICE check is performed, and ICE establishes a channel between parties.&lt;/li&gt;
&lt;li&gt;DTLS handshake is performed. If there are media transported, the SRTP uses the keys that were exported at the DTLS handshake step.&lt;/li&gt;
&lt;li&gt;All peers have secure channels with keys that are not known publicly.&lt;/li&gt;
&lt;li&gt;Exchange Keys between the peers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Applications that use WebRTC
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Google Meet/ Google Hangout&lt;/li&gt;
&lt;li&gt;Facebook Messenger&lt;/li&gt;
&lt;li&gt;Discord&lt;/li&gt;
&lt;li&gt;Amazon Chime&lt;/li&gt;
&lt;li&gt;....&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For more, you can check out this link for a list of apps that use WebRTC&lt;br&gt;
&lt;a href="http://www.webrtcworld.com/webrtc-list.aspx"&gt;http://www.webrtcworld.com/webrtc-list.aspx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>realtime</category>
    </item>
    <item>
      <title>WebRTC - The technology that powers Google Meet/Hangout, Facebook Messenger and Discord</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Mon, 20 Jul 2020 21:30:49 +0000</pubDate>
      <link>https://dev.to/calvinqc/webrtc-the-technology-that-powers-google-meet-hangout-facebook-messenger-and-discord-4j67</link>
      <guid>https://dev.to/calvinqc/webrtc-the-technology-that-powers-google-meet-hangout-facebook-messenger-and-discord-4j67</guid>
      <description>&lt;p&gt;&lt;strong&gt;Here is what happens during a P2P connection, and all you need to know about Web Real-Time Communication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Everything you need to know about Web RTC in 9 minutes&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  History of Real-time Communication
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Around the 2010s, real-time communication was only available using additional software, plugins, or Adobe Flash.&lt;/li&gt;
&lt;li&gt;In 2013, the first cross-browser video call between Chrome &amp;amp; Firefox was introduced.&lt;/li&gt;
&lt;li&gt;In 2014, the first cross-browser data transfer occurred, opening to a new-emerging trend in real-time communication via the client-side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today, it is known as the Web RTC that we use every day in Chrome, Mozilla Firefox, Opera, Safari, Edge, iOS, and Android.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;WebRTC stands for Web Real-Time Communication, which is a networking technology introduced in 2011 by Google to enable real-time audio, video, and data transmission across the web and native browsers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Its mission is to enable rich, high-quality RTC applications to be developed for the browser, mobile platforms, and IoT devices, and allow them all to communicate via a common set of protocols."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;WebRTC allows web apps to create Peer-To-Peer communication. WebRTC is a vast topic, so in this post, we'll focus on the following issues of WebRTC:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why do developers &amp;amp; companies love Web RTC?&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What happens during the P2P connection&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signaling&lt;/li&gt;
&lt;li&gt;NATs &amp;amp; ICE&lt;/li&gt;
&lt;li&gt;STUN &amp;amp; TURN Server&lt;/li&gt;
&lt;li&gt;VP9 Video Codec&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WebRTC APIs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  Why do developers &amp;amp; companies love Web RTC?
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Free open source&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It provides browsers with end-to-end direct communication and allows developers to facilitate this connection easily.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Speed Enhancement&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No longer needs to be routed through a server; it reduces latency and bandwidth consumption.&lt;/li&gt;
&lt;li&gt;Direct communication improves the speed of data transfer &amp;amp; file sharing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No third party app required&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requiring no additional software, plugins, or continuous server involvement (Well, it does, but only in the beginning, you will know why later)&lt;/li&gt;
&lt;li&gt;Easily be embedded in any websites and connect peers across the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Easy to implement&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less time and effort to facilitate peer-to-peer (P2P) connection.&lt;/li&gt;
&lt;li&gt;All the functionality can be done through the client-side.
Developers just need to download a WebRTC compatible browser and use&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compatible&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supported by most popular browsers: Microsoft Edge, Google Chrome, Mozilla Firefox, Safari, Safari, Opera, Vivaldi.&lt;/li&gt;
&lt;li&gt;Supported by Android, Chrome OS, Firefox OS, BlackBerry 10, iOS, Tizen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provide a safe connection across many browsers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encryption is mandatory for all of the WebRTC components.&lt;/li&gt;
&lt;li&gt;Since it is not a plugin, it runs inside the browser's sandbox without creating a new process so that no malware can get into the user's system.&lt;/li&gt;
&lt;li&gt;No need to keep track of the updates. With the automatic updates of the browser's version, the user gets the patch as soon as it is available.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  What happens during the P2P connection
&lt;/h1&gt;

&lt;p&gt;Image by PubNubTo connect two browsers, Web RTC is required to perform five steps to set up a P2P connection.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Signal processing to remove ambient noise from the audio or video.&lt;/li&gt;
&lt;li&gt;Codec handling to compress and decompress the audio or video.&lt;/li&gt;
&lt;li&gt;Routing from one peer to another through firewalls, (NATs), and relays to create an Interactive Connectivity Establishment (ICE)&lt;/li&gt;
&lt;li&gt;User data is encrypted before transmitting across connections.&lt;/li&gt;
&lt;li&gt;Managing bandwidth to the user what each peer has to give&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Signaling
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;P2P connections in the browser are established by a server to ensure all peers agree to the session.&lt;/li&gt;
&lt;li&gt;Information like session keys, error messages, media metadata, codecs, bandwidth, and public IP address and ports are shared between peers to create the connection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The server&lt;/strong&gt; signals to both peers to determine what media format to use and what each peer wants to send to the other.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fty0arvc09kvgpeeedvh2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fty0arvc09kvgpeeedvh2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Network Address Translations (NATs) and ICE
&lt;/h1&gt;

&lt;p&gt;NATs translate a private IP address found on devices like a home router to a public IP address. Firewalls and NATs slow the process by blocking specific protocols or ports. The solution WebRTC uses is a framework called ICE.&lt;br&gt;
ICE establishes a P2P connection over the internet by trying all connections in parallel and selecting the most efficient path. There are two types of connections: &lt;strong&gt;STUN &amp;amp; TURN&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  STUN Servers
&lt;/h1&gt;

&lt;p&gt;It first works connecting through a STUN (Session Traversal Utilities for NAT) server to get a direct link through the network address.&lt;/p&gt;

&lt;p&gt;A STUN server provides the requestor a public IP address to communicate with others. Its purpose is to help a requestor answer the question, "What's my IP Address?"&lt;/p&gt;

&lt;h2&gt;
  
  
  How STUN servers work
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjca6kacmkgeg6hefd7dc.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjca6kacmkgeg6hefd7dc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To set up a connection with other peers, an endpoint is required to know its public IP to share with others.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When an endpoint (Calvin) is behind a NAT/Firewall, it can only identify its local IP address, and the other (Elana) cannot connect to the local IP because of the firewall security.&lt;/li&gt;
&lt;li&gt;This endpoint will ask for help from the STUN server to provide its public IP address and a type of NAT.&lt;/li&gt;
&lt;li&gt;The other endpoint (Elana) can attempt the connection between the two using the given public IP address from the STUN server.&lt;/li&gt;
&lt;li&gt;If successful, media will flow directly to each endpoint without a 3rd party or another server.&lt;/li&gt;
&lt;li&gt;For security, all STUN servers will be dropped and wait for the next query.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Limitations - Symmetric NAT
&lt;/h1&gt;

&lt;p&gt;However, the situation above may &lt;em&gt;sometimes fail&lt;/em&gt;, and the PORT and IP number will be changed.&lt;/p&gt;

&lt;p&gt;This situation is called "symmetric NAT" as the public IP address of the STUN server does not have enough capability to establish connectivity here, as the port would also need a translation.&lt;/p&gt;

&lt;p&gt;Some routers use Symmetric NAT, which is made to add another security layer to the endpoint or avoid many strangers to connect to your device. A Symmetric NAT not only translates the IP address from private to public but also translates ports.&lt;/p&gt;

&lt;p&gt;In other words, the router will only accept connections from known peers that the user previously connected to. Hence, another solution is made to ensure that the connection between two peers is successful is through the TURN server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why STUN servers are useful
&lt;/h1&gt;

&lt;p&gt;As a protocol, STUN is super fast, lightweight, and straightforward. It allows the media to travel directly to each other in a short time. STUN is beneficial to speed up the connection and get the result faster in real-time.&lt;/p&gt;

&lt;p&gt;The scenario is similar when the user is using LAN to download the data, which is faster than downloading from the Wi-fi. Most importantly, it allows the media to travel directly between both endpoints. STUN can be used publicly and free.&lt;/p&gt;

&lt;h1&gt;
  
  
  TURN Servers
&lt;/h1&gt;

&lt;p&gt;TURN (Traversal Using Relays around NAT) server acts as relay servers incase the peer-to-peer connection dies. While STUN servers are used to establish the connection, TURN servers remain active throughout the association.&lt;/p&gt;

&lt;p&gt;A TURN server keeps relaying the media between the WebRTC peers. That is why the term "relay" is used to define TURN.&lt;/p&gt;

&lt;h2&gt;
  
  
  How TURN servers work
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmu1qcuy8h8t951caxhk2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmu1qcuy8h8t951caxhk2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This relay server is used to relay traffic if the STUN server fails, and it also &lt;strong&gt;has the STUN's functions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The TURN server is a STUN server with transmitting capability built-in. More specifically, TURN is used to relay audio/video/data streaming between peers, not signaling data.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Follow the steps for STUN Servers&lt;/li&gt;
&lt;li&gt;If STUN fails, an end-user will create a connection with a TURN server, inform all peers to send data to the server, which is in charge of transferring data to the first end-user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One main reason why a STUN server is always used first is that the TURN server is too expensive, and uses massive bandwidth if HD Video is streamed online.&lt;/p&gt;

&lt;h1&gt;
  
  
  VP9 Video Codec
&lt;/h1&gt;

&lt;p&gt;One of the main features, why many people start to use WebRTC, is for video streaming. As live video becomes more mainstream and starts getting higher quality, it requires data transfer to be faster or the packet size to be smaller to be easily transferred.&lt;/p&gt;

&lt;p&gt;That is when VP9 Video Codec takes place to compress and decompress the audio or video. It helps stream video quicker and more apparent. By supporting VP8, Safari 12.1 can exchange live video with other peers.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faik6ikypshs5ojhj1cpt.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faik6ikypshs5ojhj1cpt.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VP9, which is an improvement from VP8, is a video compression format owned by Google and created by On2 Technologies.&lt;/p&gt;

&lt;p&gt;The main feature is to conceal packet loss and clean up noisy images, as well as capture and playback capabilities across multiple platforms.&lt;/p&gt;

&lt;p&gt;With VP9, users can use WebRTC to stream a 720p video without packet loss or delay. It can also support a 1080p video call at the same bandwidth and helps reduce poor connections and data usage to avoid expensive costs for users.&lt;/p&gt;




&lt;h1&gt;
  
  
  JavaScript APIs
&lt;/h1&gt;

&lt;p&gt;There are three main Javascript APIs that handle audio capturing, video conferencing, and data transmission:&lt;/p&gt;

&lt;h2&gt;
  
  
  MediaStream
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Utilizes a user's camera and microphone to capture and stream audio and video. Using this API allows you to get access to input devices such as the microphone and the web camera.&lt;/li&gt;
&lt;li&gt;When a developer integrates WebRTC into their website, they can create constraints on how they want the audio and video streamed. Limitations like the frame rate, size of the video frame, resolutions, and much more.&lt;/li&gt;
&lt;li&gt;This API was provided as part of HTML 5, whereas the other two APIs are explicitly offered for WebRTC.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  RTCPeerConnection
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Send the captured stream of audio and video in real-time across the internet to another WebRTC endpoint. Using these APIs enables users to transmit audio and video captured by getUserMedia to other peers.&lt;/li&gt;
&lt;li&gt;Has features to connect to a remote peer, maintain and monitor the connection, and close the connection once after it's done.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  RTCDataChannel
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Transmit arbitrary data. Each data channel is associated with an RTCPeerConnection.&lt;/li&gt;
&lt;li&gt;Built-in security (DTLS) and congestion control.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;p&gt;One of the security risks in any real-time communication application may raise during the transmission of data. Eventually, encryption is a mandatory feature of WebRTC and is enforced on all components.&lt;/p&gt;

&lt;p&gt;WebRTC uses two standardized encrypting protocols:&lt;/p&gt;

&lt;h2&gt;
  
  
  Datagram Transport Layer Security (DTLS)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A standardized protocol that is built in a browser. It's used to encrypt data streams. It is based on the Transport Layer Protocol (TLP).&lt;/li&gt;
&lt;li&gt;Preserves the semantics of the transport because DTLS uses User Data Protocol (UDP).&lt;/li&gt;
&lt;li&gt;It is an extension of Secure Sockets Layer (SSL); any SSL protocol could be used to secure WebRTC data allowing end-to-end encryption.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Secure Real-time Transport Protocol (SRTP)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Used to encrypt media streams.&lt;/li&gt;
&lt;li&gt;It is an extension to Real-Time Transport Protocol (RTP), which does not have any built-in security mechanisms.
Adds protection, integrity, and message authentication to the RTP.&lt;/li&gt;
&lt;li&gt;Downside: While it provides encryption for the RTP packets, it does not encrypt the header.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Steps to secure a link between 2 peers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Initiates the signaling process exchanges the metadata between two peers.&lt;/li&gt;
&lt;li&gt;ICE check is performed, and ICE establishes a channel between parties.&lt;/li&gt;
&lt;li&gt;DTLS handshake is performed. If there are media transported, the SRTP uses the keys that were exported at the DTLS handshake step.&lt;/li&gt;
&lt;li&gt;All peers have secure channels with keys that are not known publicly.&lt;/li&gt;
&lt;li&gt;Exchange Keys between the peers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Applications that use WebRTC
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Google Meet/ Google Hangout&lt;/li&gt;
&lt;li&gt;Facebook Messenger&lt;/li&gt;
&lt;li&gt;Discord&lt;/li&gt;
&lt;li&gt;Amazon Chime&lt;/li&gt;
&lt;li&gt;....&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For more, you can check out this link for a list of apps that use WebRTC&lt;br&gt;
&lt;a href="http://www.webrtcworld.com/webrtc-list.aspx" rel="noopener noreferrer"&gt;http://www.webrtcworld.com/webrtc-list.aspx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow me &lt;a href="https://medium.com/@calvinqc" rel="noopener noreferrer"&gt;here&lt;/a&gt; to get the latest blog posts&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>The Easiest Docker &amp; Docker-compose Setup on Compute Engine</title>
      <dc:creator>Calvin Nguyen</dc:creator>
      <pubDate>Mon, 20 Jul 2020 21:28:49 +0000</pubDate>
      <link>https://dev.to/calvinqc/the-easiest-docker-docker-compose-setup-on-compute-engine-1op1</link>
      <guid>https://dev.to/calvinqc/the-easiest-docker-docker-compose-setup-on-compute-engine-1op1</guid>
      <description>&lt;h1&gt;
  
  
  Inspiration
&lt;/h1&gt;

&lt;p&gt;Whenever I created a new Compute Engine and have to set up Docker again, I usually go to multiple web pages to find the right command to install Docker and Docker-compose.&lt;/p&gt;

&lt;p&gt;It usually takes me more than 5' just to find the command line and set up. Sometimes some websites might not have what you want. So I created this blog to help me and maybe you to setup Docker and Docker-compose in less than a minute.&lt;/p&gt;

&lt;h1&gt;
  
  
  Requirement
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;In this tutorial, I’d assume you already had a new Compute Engine running Debian (as it’s the default), and get ready to run your app with Docker.&lt;/li&gt;
&lt;li&gt;You have knowledge with Docker and it’s better that your server has Dockerfile and/or docker-compose.yml&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;ssh into your virtual machine either via command line or Cloud Console.&lt;/li&gt;
&lt;li&gt;Login as admin: &lt;code&gt;$ sudo -s&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If you don’t do sudo -s first, you need to have sudo in every command&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The 1 Line Command
&lt;/h1&gt;

&lt;p&gt;If you already know what you’re doing but getting somewhere, here is a 1-line command that will get you Docker &amp;amp; Docker-compose set up for Compute Engine.&lt;br&gt;
I also make commands below for you to see what’s going on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt update &amp;amp;&amp;amp; apt install --yes apt-transport-https ca-certificates curl gnupg2 software-properties-common &amp;amp;&amp;amp; curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - &amp;amp;&amp;amp; add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" &amp;amp;&amp;amp; apt update &amp;amp;&amp;amp; apt install --yes docker-ce &amp;amp;&amp;amp; curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose &amp;amp;&amp;amp; chmod +x /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Docker
&lt;/h1&gt;

&lt;p&gt;If you prefer doing separately, do the following Commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ apt update
$ apt install --yes apt-transport-https ca-certificates curl gnupg2 software-properties-common
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
$ add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
$ apt update
$ apt install --yes docker-ce
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker
$ docker info
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Executing the Docker Command without sudo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Whenever you run docker, you either have to add sudo or run &lt;code&gt;sudo -s&lt;/code&gt;, and it annoys me sometimes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the commands below: &lt;code&gt;$ sudo usermod -aG docker $USER&lt;/code&gt;&lt;br&gt;
Then log in again, you will be able to run docker without sudo&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Docker-compose
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Why do we need docker-compose
&lt;/h2&gt;

&lt;p&gt;When you run &lt;code&gt;docker run ...&lt;/code&gt;, your app will keep running UNTIL you close the browser. This is inefficient because you don’t want to leave your tab open forever. So we will use docker-compose, and it’ll run your app in the background&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;$ curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ chmod +x /usr/local/bin/docker-compose&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;docker-compose --version&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Make sure you have a docker-compose.yml in your directory&lt;br&gt;
Run &lt;code&gt;docker-compose up --build&lt;/code&gt;&lt;br&gt;
After starting your app successfully, run &lt;code&gt;docker-compose up -d&lt;/code&gt;&lt;br&gt;
Otherwise, check the error and fix the bug&lt;/p&gt;

&lt;h1&gt;
  
  
  Congratulation
&lt;/h1&gt;

&lt;p&gt;Now, you’re able to run your app in the background and use it using the public IPv4!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>googlecloud</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
