<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Gaurav Saini</title>
    <description>The latest articles on Forem by Gaurav Saini (@sainig).</description>
    <link>https://forem.com/sainig</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%2F325223%2F4150a45d-fc8e-4a3d-bfb2-a3ce7006ed93.png</url>
      <title>Forem: Gaurav Saini</title>
      <link>https://forem.com/sainig</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sainig"/>
    <language>en</language>
    <item>
      <title>Help needed with subrouting in Go</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Sun, 21 Apr 2024 10:41:05 +0000</pubDate>
      <link>https://forem.com/sainig/help-needed-with-subroutine-in-go-4obc</link>
      <guid>https://forem.com/sainig/help-needed-with-subroutine-in-go-4obc</guid>
      <description>&lt;h2&gt;
  
  
  Hello 👋
&lt;/h2&gt;

&lt;p&gt;I've started learning Go a couple days ago. Currently, I'm building Rest APIs using &lt;code&gt;net/http&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;I have figured out most of the basic stuff, but struggling a bit with subrouting. When I add a subrouter using like this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mux1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mux1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&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="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mux2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mux2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&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="n"&gt;mux1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mux2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;I'm trying to add a protected set of routes to a router using a middleware. But, the routes defined in the subrouter are not accessible without adding a trailing slash in the URL when making the request. eg:&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%2Fuploads%2Farticles%2Fqln6w6l717hazl3gvp8i.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%2Fuploads%2Farticles%2Fqln6w6l717hazl3gvp8i.png" alt="Screenshot of curl outputs with and without trailing slash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Code
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="c"&gt;// cmd/main/main.go&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="s"&amp;gt;"rest-api/internal/middleware"&amp;lt;/span&amp;gt;
&amp;lt;span class="s"&amp;gt;"rest-api/internal/routes"&amp;lt;/span&amp;gt;
&amp;lt;span class="s"&amp;gt;"rest-api/internal/utils"&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;middlewareStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="k"&amp;gt;var&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;v1Router&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;http&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;NewServeMux&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;()&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;v1Router&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Handle&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"/v1/"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;http&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;StripPrefix&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"/v1"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;routes&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;EchoRouter&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;()))&amp;lt;/span&amp;gt;

&amp;lt;span class="k"&amp;gt;var&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;usersRouter&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;routes&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;UsersRouter&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;()&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;v1Router&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Handle&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"/users/"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;http&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;StripPrefix&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"/users"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;usersRouter&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;))&amp;lt;/span&amp;gt;

&amp;lt;span class="k"&amp;gt;var&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;server&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;&amp;amp;amp;&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;http&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Server&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;{&amp;lt;/span&amp;gt;
    &amp;lt;span class="n"&amp;gt;Addr&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;:&amp;lt;/span&amp;gt;    &amp;lt;span class="s"&amp;gt;":8080"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt;
    &amp;lt;span class="n"&amp;gt;Handler&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;:&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;middlewareStack&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;v1Router&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;),&amp;lt;/span&amp;gt;
&amp;lt;span class="p"&amp;gt;}&amp;lt;/span&amp;gt;

&amp;lt;span class="n"&amp;gt;fmt&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Println&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"starting server on port 8080"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;server&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;ListenAndServe&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;()&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// internal/routes/users.go&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="s"&amp;gt;"rest-api/internal/middleware"&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;UsersRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;usersMux&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;usersMux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="k"&amp;gt;var&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;protectedMux&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;http&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;NewServeMux&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;()&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;protectedMux&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;HandleFunc&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"POST /"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;createUser&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;usersMux&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Handle&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"/"&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;middleware&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;IsAuthenticated&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;protectedMux&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;))&amp;lt;/span&amp;gt;

&amp;lt;span class="k"&amp;gt;return&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;usersMux&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users list"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="k"&amp;gt;if&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;err&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;!=&amp;lt;/span&amp;gt; &amp;lt;span class="no"&amp;gt;nil&amp;lt;/span&amp;gt; &amp;lt;span class="p"&amp;gt;{&amp;lt;/span&amp;gt;
    &amp;lt;span class="n"&amp;gt;res&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;WriteHeader&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;http&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;StatusBadRequest&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt;
    &amp;lt;span class="n"&amp;gt;res&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Write&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;([]&amp;lt;/span&amp;gt;&amp;lt;span class="kt"&amp;gt;byte&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;err&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Error&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;()))&amp;lt;/span&amp;gt;
    &amp;lt;span class="k"&amp;gt;return&amp;lt;/span&amp;gt;
&amp;lt;span class="p"&amp;gt;}&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;res&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;WriteHeader&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;http&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;StatusCreated&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;res&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Write&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;([]&amp;lt;/span&amp;gt;&amp;lt;span class="kt"&amp;gt;byte&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;"new user created, name: "&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;+&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;newUser&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Name&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;+&amp;lt;/span&amp;gt; &amp;lt;span class="s"&amp;gt;", email: "&amp;lt;/span&amp;gt; &amp;lt;span class="o"&amp;gt;+&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;newUser&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Email&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;))&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  PS&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;I can achieve the desired behaviour by using the &lt;code&gt;/users&lt;/code&gt; prefix in the &lt;code&gt;users.go&lt;/code&gt; file instead of the &lt;code&gt;main.go&lt;/code&gt; file, but I was wondering if it can be done this way too 🤔 &lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
      <category>help</category>
      <category>go</category>
      <category>restapi</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Help - How to run npm builds using docker?</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Thu, 17 Aug 2023 18:41:15 +0000</pubDate>
      <link>https://forem.com/sainig/help-how-to-run-npm-builds-using-docker-5eec</link>
      <guid>https://forem.com/sainig/help-how-to-run-npm-builds-using-docker-5eec</guid>
      <description>&lt;h2&gt;
  
  
  Hello 👋
&lt;/h2&gt;

&lt;p&gt;I want to run &lt;code&gt;npm run build&lt;/code&gt; scripts using a &lt;code&gt;Dockerfile/docker-compose.yml&lt;/code&gt; file and get the build output on my host file system. Is there any way I can achieve this?&lt;/p&gt;

&lt;p&gt;Basically, what I'm looking for is to run a single command, like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up

&lt;span class="c"&gt;# OR&lt;/span&gt;

docker build &lt;span class="nt"&gt;-t&lt;/span&gt; my-builder &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker run my-builder

&lt;span class="c"&gt;# or maybe even a shell script&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which would spin up a container, run the &lt;code&gt;npm build&lt;/code&gt; script inside the container, and with the help of either a volume or bind mount (or some other concept I'm not aware of 😅) put the build output on a specified directory on the host file system.&lt;/p&gt;

&lt;p&gt;Any help would be greatly appreciated 🙏.&lt;/p&gt;

&lt;p&gt;Thanks!!&lt;/p&gt;

</description>
      <category>help</category>
      <category>docker</category>
      <category>npm</category>
      <category>react</category>
    </item>
    <item>
      <title>Help: How to watch for changes in local dependencies in monorepo?</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Thu, 13 Jul 2023 17:26:22 +0000</pubDate>
      <link>https://forem.com/sainig/help-how-to-watch-for-changes-in-local-dependencies-in-monorepo-8pk</link>
      <guid>https://forem.com/sainig/help-how-to-watch-for-changes-in-local-dependencies-in-monorepo-8pk</guid>
      <description>&lt;p&gt;Hey folks,&lt;/p&gt;

&lt;p&gt;I am currently setting up a monorepo project using &lt;code&gt;pnpm&lt;/code&gt;, &lt;code&gt;turborepo&lt;/code&gt;, &lt;code&gt;typescript&lt;/code&gt;, and &lt;code&gt;nestjs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The folder structure is like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└── my-ts-monorepo/
    ├── apps/
    │   └── server
    └── libs/
        └── utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;utils&lt;/code&gt; library is added as a dependency in the &lt;code&gt;server&lt;/code&gt; application.&lt;br&gt;
&lt;code&gt;utils&lt;/code&gt; is a simple typescript library with some math functions and &lt;code&gt;server&lt;/code&gt; is a NestJS REST API.&lt;/p&gt;

&lt;p&gt;Everything is working fine except for one thing. While running the dev server, if I make any code changes in the &lt;code&gt;utils&lt;/code&gt; library, the changes are not picked up by the &lt;code&gt;server&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;I tried running the &lt;code&gt;tsc&lt;/code&gt; build for the &lt;code&gt;utils&lt;/code&gt; library with the &lt;code&gt;--watch&lt;/code&gt; flag, but no luck there also.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;dev&lt;/code&gt; scripts look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"turbo run dev"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apps/server/package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nest start --watch"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;libs/utils/package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc --watch"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please help me so that the NestJS dev server can pick up code changes in the &lt;code&gt;utils&lt;/code&gt; dependency also.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
      <category>help</category>
      <category>typescript</category>
      <category>nestjs</category>
      <category>monorepo</category>
    </item>
    <item>
      <title>How to build microservices with Docker - BONUS!!</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Wed, 28 Jun 2023 13:01:42 +0000</pubDate>
      <link>https://forem.com/sainig/how-to-build-microservices-with-docker-bonus-4b89</link>
      <guid>https://forem.com/sainig/how-to-build-microservices-with-docker-bonus-4b89</guid>
      <description>&lt;h2&gt;
  
  
  Hello there 👋
&lt;/h2&gt;

&lt;p&gt;This is probably the last part in microservices basics series, but certainly not the least. Today we're going to look at how we can scale up individual services and apply load balancing. This will give a major performance boost in high traffic scenarios and increase the up-time of our application.&lt;/p&gt;

&lt;p&gt;Without further ado, let's dive in&lt;/p&gt;

&lt;h2&gt;
  
  
  Spawning multiple containers
&lt;/h2&gt;

&lt;p&gt;First things first, we have to create/spawn multiple containers of the service we want to apply load balancing to. Let's use the Products service for this experiment.&lt;/p&gt;

&lt;p&gt;We can make changes to the &lt;code&gt;products&lt;/code&gt; service definition in the &lt;code&gt;docker-compose.services.yml&lt;/code&gt; file as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;products/docker-compose.yml&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
  &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
  &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;    &lt;span class="c1"&gt;# new option "scale" to tell docker-compose to spawn 3 containers for this service&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, when we bring up the services using the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose &lt;span class="nt"&gt;--file&lt;/span&gt; docker-compose.services.yml up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we see the logs indicating there are 3 container running for the products service.&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%2Fuploads%2Farticles%2F9rcaq1oo58ry8wwex5u8.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%2Fuploads%2Farticles%2F9rcaq1oo58ry8wwex5u8.png" alt="Logs showing multiple containers at startup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome!! we're already halfway there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Load Balancing
&lt;/h2&gt;

&lt;p&gt;Remember when I talked about &lt;a href="https://dev.to/sainig/how-to-build-microservices-with-docker-the-orchestration-5d0f#:~:text=This%20is%20how%20we%20define%20a%20server%20group."&gt;defining server groups&lt;/a&gt; in the &lt;code&gt;nginx.conf&lt;/code&gt; file. Well, so far we only had one server in the group, so calling it a group didn't make much sense.&lt;/p&gt;

&lt;p&gt;But now that we have multiple containers running, in other words, multiple servers running, we can use the server group to its fullest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upstream products {
  server microservices-shop_products_1:4000;
  server microservices-shop_products_2:4000;
  server microservices-shop_products_3:4000;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is as simple as that! we have achieved load balancing among our 3 products service containers.&lt;/p&gt;

&lt;p&gt;And, we have the logs to verify that&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%2Fuploads%2Farticles%2Fv2fn8izjjyzbtyeitcjp.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%2Fuploads%2Farticles%2Fv2fn8izjjyzbtyeitcjp.png" alt="Logs demonstrating load balancing in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These logs ☝️ are generated when we send multiple requests to any &lt;code&gt;/products&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;Since, we've only specified the names of the servers (container names and port numbers), the default algorithm used by Nginx is a Round Robin algorithm.&lt;/p&gt;

&lt;p&gt;You can read more about the supported algorithms &lt;a href="https://www.nginx.com/faq/what-are-the-load-balancing-algorithms-supported/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wanna see more
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Also, if you have any suggestions, improvements, or anything more in general that you'd like to see in this series, please add a comment. I'll try my best to include it here.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this series and learnt something new.&lt;/p&gt;

&lt;p&gt;Feel free to post any questions you have in the comments below.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>docker</category>
      <category>nginx</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to build microservices with Docker - The Orchestration</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Tue, 27 Jun 2023 16:47:58 +0000</pubDate>
      <link>https://forem.com/sainig/how-to-build-microservices-with-docker-the-orchestration-5d0f</link>
      <guid>https://forem.com/sainig/how-to-build-microservices-with-docker-the-orchestration-5d0f</guid>
      <description>&lt;p&gt;Hello everyone!&lt;br&gt;
So far in this series we have looked at the &lt;a href="https://dev.to/sainig/how-to-build-microservices-with-docker-introduction-4939"&gt;high level architecture&lt;/a&gt; of the app we're building and the &lt;a href="https://dev.to/sainig/how-to-build-microservices-with-docker-the-services-fe3"&gt;code for the 4 services&lt;/a&gt; that are part of our simple shop application. And today, we'll look at the &lt;code&gt;docker-compose&lt;/code&gt; files for running the full application and send in some requests to see if it goes boom 💥.&lt;/p&gt;

&lt;p&gt;Again, the full code is in the &lt;a href="https://github.com/saini-g/microservices-shop" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt; if you want to jump straight to the code.&lt;/p&gt;

&lt;p&gt;Let's get started&lt;/p&gt;




&lt;h2&gt;
  
  
  Before we begin
&lt;/h2&gt;

&lt;p&gt;Okay, so before we start, I'll just quickly explain how I've organized my &lt;code&gt;docker-compose&lt;/code&gt; files and why I did what I did.&lt;/p&gt;

&lt;p&gt;I saw 2 approaches to writing the compose files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Putting all the services in a single file.&lt;/li&gt;
&lt;li&gt;Logically grouping the services in separate files based on their nature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the first approach, as the description suggests, we would have just one &lt;code&gt;docker-compose.yml&lt;/code&gt; file and running the application would be super easy. Just do &lt;code&gt;docker-compose up&lt;/code&gt; and that's it.&lt;br&gt;
But, I found writing the services a bit cumbersome this way because I had to remember to add the &lt;code&gt;depends_on&lt;/code&gt; option in many services definitions in order to avoid any breakdowns due to the services starting before the dependencies are running, or the Nginx Gateway looking for the services and finding nothing.&lt;/p&gt;

&lt;p&gt;To avoid adding all the dependencies manually in the compose files, I decided to go with the second approach and execute each file one-by-one in a particular order. You'll see what I mean in a minute.&lt;/p&gt;

&lt;p&gt;This way, we just have to ask ourselves one question before writing a service definition&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Is the service an application dependency, a setup/pre-requisite thing, or a part of the application code (like the products service or the orders service)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and then, put the service definition in the corresponding &lt;code&gt;docker-compose&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;I personally find this approach much better in the long term from a maintainability POV.&lt;/p&gt;

&lt;p&gt;And with that out of the way, let's get started for real this time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setup and Pre-requisites
&lt;/h2&gt;

&lt;p&gt;This file is dedicated to any items that we need to take care of even before we start with running the application. Such as setting up the networks, volumes, migrating and seeding databases, etc. I'm creating a network and a volume, like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;shop-intranet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;shop-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and then, to run this file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;--file&lt;/span&gt; docker-compose.setup.yml up


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

&lt;/div&gt;




&lt;h2&gt;
  
  
  Application Dependencies
&lt;/h2&gt;

&lt;p&gt;Any tools/applications that we need to run before starting our main application code should be placed in this file, eg: databases, cache, message brokers, etc.&lt;br&gt;
I'm using this file to start the &lt;code&gt;nats-broker&lt;/code&gt; used for relaying messages between the orders and the notifications services.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nats-broker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nats:2.9-alpine&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and then, to run this file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;--file&lt;/span&gt; docker-compose.deps.yml up


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

&lt;/div&gt;




&lt;h2&gt;
  
  
  Application Services
&lt;/h2&gt;

&lt;p&gt;This file is for our backend services, that we've written. Here, we'll put all our services that make up the application. A single service definition will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auth/docker-compose.yml&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
  &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and we can also associate the services to the network and volume we created earlier, like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auth/docker-compose.yml&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
  &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
  &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;shop-intranet&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;shop-data:/app&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and then, to run this file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;--file&lt;/span&gt; docker-compose.services.yml up


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

&lt;/div&gt;




&lt;h2&gt;
  
  
  Nginx Gateway
&lt;/h2&gt;

&lt;p&gt;This file contains our Nginx server, and will open up an entrypoint to our application backend from the outside internet.&lt;/p&gt;

&lt;p&gt;First, let's look at the &lt;code&gt;nginx.conf&lt;/code&gt; file where we put the configuration for our server. Most of the file is a pretty basic Nginx configuration. So, I'll explain the parts specific to our app.&lt;/p&gt;

&lt;p&gt;This is how we define a server group.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

upstream products {
  server microservices-shop_products_1:4000;
}


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

&lt;/div&gt;

&lt;p&gt;A server group is a way to name an address (IP/hostname and port number) so that we can use it later in our remaining configuration. We'll look at how we can use this in a moment.&lt;br&gt;
Here the hostname is the name of the running container and &lt;code&gt;4000&lt;/code&gt; is the port number inside that container.&lt;/p&gt;

&lt;p&gt;We can definer the other server groups for Orders and Products services in the exact same manner.&lt;/p&gt;

&lt;p&gt;Then we can define the routing for our services. For that we define a location block. Let's start with the simplest one.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

location ^~ /products/ {
  proxy_pass http://products/;
}


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

&lt;/div&gt;

&lt;p&gt;Here, &lt;code&gt;/products/&lt;/code&gt; is the path prefix of the incoming requests and in the second line &lt;code&gt;products&lt;/code&gt; is the name of the server group we defined earlier. So, this configuration piece means that whatever requests are coming in to &lt;code&gt;/products/&amp;lt;anything&amp;gt;&lt;/code&gt;, forward them to the server group named &lt;code&gt;products&lt;/code&gt;. The &lt;code&gt;proxy_pass&lt;/code&gt; directive is used to forward requests is such a way.&lt;br&gt;
One more thing, before forwarding the request, Nginx will strip the path prefix from the request, so an incoming &lt;code&gt;/products/search&lt;/code&gt; request will reach the products service as only &lt;code&gt;/search&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, we have the orders service server group.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

location ^~ /orders/ {
  auth_request /auth/verify;
  proxy_pass http://orders/;
}


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

&lt;/div&gt;

&lt;p&gt;The new thing here is &lt;code&gt;auth_request /auth/verify;&lt;/code&gt;. This line means that before forwarding the request to the &lt;code&gt;orders&lt;/code&gt; server group, check for user authentication using the &lt;code&gt;/auth/verify&lt;/code&gt; endpoint. So, Nginx internally makes a request to the auth service, and if the response is &lt;code&gt;200 OK&lt;/code&gt;, then the request is forwarded to the orders service, and if the response is &lt;code&gt;401 Unauthorized&lt;/code&gt;, then Nginx sends also back a &lt;code&gt;401&lt;/code&gt; to the requester.&lt;/p&gt;

&lt;p&gt;Finally, the most difficult one for me was the auth server group&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

location ^~ /auth/ {
  internal;
  proxy_pass http://auth/;

  proxy_pass_request_body off;
  proxy_set_header Content-Length "";
  proxy_set_header X-Original_URI $request_uri;
  proxy_set_header Authorization $http_authorization;
}


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;internal&lt;/code&gt; at the start means that this location is accessible by Nginx internally only. If we make any request to &lt;code&gt;/auth/anything&lt;/code&gt;, we'll get back a &lt;code&gt;404 Not Found&lt;/code&gt; response.&lt;/p&gt;

&lt;p&gt;Then, there's a bunch of gibberish looking stuff. Let's look at the meaning of each line one by one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;proxy_pass_request_body off;&lt;/code&gt; - Nginx will remove the request body before forwarding the request.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_set_header Content-Length "";&lt;/code&gt; - Setting the &lt;code&gt;Content-Length&lt;/code&gt; header to blank. Since we've removed the request body, there's no point in having a non-zero content length.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_set_header X-Original_URI $request_uri;&lt;/code&gt; - Set the &lt;code&gt;X-Original_URI&lt;/code&gt; header to &lt;code&gt;$request_uri&lt;/code&gt;, which is a variable provided by Nginx and the value is the current request URL. This is to let Nginx know where to forward the request once authentication is successful.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Authorization $http_authorization&lt;/code&gt; - Setting the &lt;code&gt;Authorization&lt;/code&gt; header, because this is what we have to verify in the auth service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is it for the &lt;code&gt;nginx.conf&lt;/code&gt; file. Now, moving on to the last piece of the puzzle.&lt;/p&gt;

&lt;p&gt;Here's the service definition for the Nginx server.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.25-alpine&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;80:80&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx.conf:/etc/nginx/nginx.conf:ro&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We're mapping the local port &lt;code&gt;80&lt;/code&gt; to the port &lt;code&gt;80&lt;/code&gt; in the Nginx container. And the &lt;code&gt;volumes&lt;/code&gt; section is used to replace the &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt; inside the container with our local &lt;code&gt;nginx.conf&lt;/code&gt; file, because that's where Nginx looks for the configuration by default.&lt;br&gt;
The &lt;code&gt;:ro&lt;/code&gt; at the end is to make it &lt;code&gt;readonly&lt;/code&gt; to prevent any modifications to the local file from inside the container. Simply put, the container can read the file, but cannot make any changes to it.&lt;/p&gt;

&lt;p&gt;and then, to run this file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;--file&lt;/span&gt; docker-compose.gateway.yml up


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

&lt;/div&gt;

&lt;p&gt;And Voila! 🤌, we have finally managed to run our microservices based application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's make some requests
&lt;/h2&gt;




&lt;h3&gt;
  
  
  &lt;code&gt;GET /products/?ids=&lt;/code&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: We can skip the &lt;code&gt;ids&lt;/code&gt; query parameter to get all the products.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl http://localhost/products/?ids&lt;span class="o"&gt;=&lt;/span&gt;2,5


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&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="s2"&gt;2&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="s2"&gt;name&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="s2"&gt;Half Sleeve Shirt&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="s2"&gt;price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keywords&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shirt&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="s2"&gt;topwear&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&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="s2"&gt;5&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="s2"&gt;name&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="s2"&gt;Sunglasses&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="s2"&gt;price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keywords&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;accessories&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="s2"&gt;sunglasses&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


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

&lt;/div&gt;




&lt;h3&gt;
  
  
  &lt;code&gt;POST /orders/&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl http://localhost/orders/ &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: secret-auth-token'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
        "userId": "saini-g",
        "productIds": ["2", "4"]
    }'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;productIds&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&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="s2"&gt;4&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="s2"&gt;totalAmount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userId&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="s2"&gt;saini-g&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="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2487&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Also, we get the logs in the console to verify that everything is running as expected:&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%2Fuploads%2Farticles%2Fq4rkwcg9dtsfth4805ju.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%2Fuploads%2Farticles%2Fq4rkwcg9dtsfth4805ju.png" alt="New order placed logs"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;That was all for today. It was a long one, so thanks a lot and congratulations to everyone who stuck till the very end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But wait!&lt;/strong&gt; I have a small bonus for all you good learners 🤩. But for that you'll have to wait for the next part 😛.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this series and learnt something new.&lt;/p&gt;

&lt;p&gt;Feel free to post any questions you have in the comments below.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>docker</category>
      <category>nginx</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to build microservices with Docker - The Services</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Mon, 26 Jun 2023 14:01:14 +0000</pubDate>
      <link>https://forem.com/sainig/how-to-build-microservices-with-docker-the-services-fe3</link>
      <guid>https://forem.com/sainig/how-to-build-microservices-with-docker-the-services-fe3</guid>
      <description>&lt;p&gt;Hello everyone and welcome back,&lt;br&gt;
Today we'll cover the second part of the microservices application - the code for the individual services.&lt;br&gt;
To quickly recall from the &lt;a href="https://dev.to/sainig/how-to-build-microservices-with-docker-introduction-4939"&gt;first part&lt;/a&gt;, the services we'll build today are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Products:&lt;/strong&gt; Used to list and search for products.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orders:&lt;/strong&gt; Used to place new orders. This is protected by the auth server so users can't place orders unless they're logged in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifications:&lt;/strong&gt; Used to notify users when a new order is placed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth:&lt;/strong&gt; Used to check user authentication before placing orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, without any more delay, let's start&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PS: The code here is incomplete, for the full code check out the &lt;a href="https://github.com/saini-g/microservices-shop"&gt;Github repo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Products Service
&lt;/h2&gt;

&lt;p&gt;This will be a simple Node, Express REST API. There's one &lt;code&gt;GET&lt;/code&gt; endpoint to list all products. The code is like:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&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="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="nx"&gt;express&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="kd"&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="nx"&gt;next&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ids&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;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;resultProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&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;ids&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;productIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&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;resultProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&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;return&lt;/span&gt; &lt;span class="nx"&gt;productIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resultProducts&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;p&gt;You'll notice we have a query parameter named &lt;code&gt;ids&lt;/code&gt;. We'll use this to fetch a subset of all the products by their id.&lt;/p&gt;

&lt;p&gt;Also, for simplicity, the complete list of products is coming from a local variable &lt;a href="https://github.com/saini-g/microservices-shop/blob/main/products/src/app.js#L41"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Orders Service
&lt;/h2&gt;

&lt;p&gt;This is also a Node, Express REST API, but not quite as simple as the products one. There's still only one &lt;code&gt;POST&lt;/code&gt; endpoint, but since it does multiple things, let's look at the code in pieces.&lt;/p&gt;

&lt;p&gt;First, we extract the &lt;code&gt;userId&lt;/code&gt; and &lt;code&gt;productIds&lt;/code&gt; from the request body and use the &lt;code&gt;productIds&lt;/code&gt; to fetch more product details (mainly prices and names) from the products service:&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;productIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&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="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;orderedProducts&lt;/span&gt; &lt;span class="p"&gt;}&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&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;PRODUCTS_APP_HOST&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/?ids=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&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="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we calculate the total amount for the order and a comma separated names list of the products:&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;totalAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;orderedProductNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for&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;product&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;orderedProducts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;totalAmount&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;orderedProductNames&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;orderedProductNames&lt;/span&gt; &lt;span class="o"&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;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we publish a message for the &lt;code&gt;nats-broker&lt;/code&gt; (we'll look at the notification service next) and send a response back to the API request. Similar to the products service, there's no database here also, so we just return a plain JSON object with a random id in the response.&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="nx"&gt;natsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;NEW_ORDER_MESSAGING_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, your order is confirmed. Products: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderedProductNames&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;productIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;userId&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;9999&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;h2&gt;
  
  
  Notifications Service
&lt;/h2&gt;

&lt;p&gt;This service is a Nats subscriber, listening for messages published to the "new order placed channel". For now, we just log the incoming messages to the console, but in a real world scenario we can notify users via SMS, Emails, etc.&lt;br&gt;
The code consists of 2 functions, one is the handler for messages and another to start the subscriber.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleMessages&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;message&lt;/span&gt;&lt;span class="p"&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error while reading messages: &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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Message received on channel "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;NEW_ORDER_MESSAGING_CHANNEL&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&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="nx"&gt;natsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;natsClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NEW_ORDER_MESSAGING_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleMessages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The &lt;code&gt;nats-client&lt;/code&gt; code
&lt;/h3&gt;

&lt;p&gt;This is a common file and can be used by any service who wants to talk to the Nats broker.&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StringCodec&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nats&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;NATS_BROKER_URL&lt;/span&gt; &lt;span class="o"&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;NATS_BROKER_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;NatsClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;codec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;codec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StringCodec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;startup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;conn&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;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NATS_BROKER_URL&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Connected to nats broker on "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getServer&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="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;codec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;callback&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;payload&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;cb&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;codec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decode&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;data&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Subscribed to messaging channel "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;channel&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;p&gt;Currently, the orders service uses the &lt;code&gt;sendMessage&lt;/code&gt; method and the notifications service uses the &lt;code&gt;subscribe&lt;/code&gt; method.&lt;/p&gt;




&lt;h2&gt;
  
  
  Auth Service
&lt;/h2&gt;

&lt;p&gt;This is again a REST API. But, just to mix things up a bit, it's built in Python using the &lt;a href="https://fastapi.tiangolo.com/"&gt;FastAPI&lt;/a&gt; framework. Currently, there's only one endpoint to verify the &lt;code&gt;Authorization&lt;/code&gt; header, which checks for a hardcoded token value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/verify"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"secret-auth-token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JSONResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_401_UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JSONResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_200_OK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;That was all for the individual services code. In the next part we'll look at the root level &lt;code&gt;docker-compose.yml&lt;/code&gt; files and the &lt;code&gt;nginx.conf&lt;/code&gt; file to start all the components of the application and make things work.&lt;/p&gt;

&lt;p&gt;I hope you'll enjoy this series and learn something new.&lt;/p&gt;

&lt;p&gt;Feel free to post any questions you have in the comments below.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>tutorial</category>
      <category>node</category>
      <category>python</category>
    </item>
    <item>
      <title>How to build microservices with Docker - Introduction</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Sun, 25 Jun 2023 09:07:59 +0000</pubDate>
      <link>https://forem.com/sainig/how-to-build-microservices-with-docker-introduction-4939</link>
      <guid>https://forem.com/sainig/how-to-build-microservices-with-docker-introduction-4939</guid>
      <description>&lt;p&gt;Hello everyone,&lt;br&gt;
Microservices are very popular these days, and rightly so. They offer a lot of flexibility and freedom to the developers. So, I decided to learn them and share my knowledge with you. I hope you know, in theory, what microservices are. If you're not familiar with the concept, &lt;a href="https://www.youtube.com/watch?v=CdBtNQZH8a4"&gt;this video&lt;/a&gt; is an excellent place to start.&lt;br&gt;
I've decided to break my journey into a series of 3-4 posts, and this is the first part.&lt;br&gt;
I'll add everything to Github, so you can check out the repo &lt;a href="https://github.com/saini-g/microservices-shop"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Let's start with a brief summary of the entire project that we'll be building. We'll make a simple e-commerce application and the high level design will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tgMedKyh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aldng23d7xar7s07pmqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tgMedKyh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aldng23d7xar7s07pmqb.png" alt="Application architecture diagram" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, there are 4 main services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Products:&lt;/strong&gt; Used to list and search for products.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orders:&lt;/strong&gt; Used to place new orders. This is protected by the auth server so users can't place orders unless they're logged in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifications:&lt;/strong&gt; Used to notify users when a new order is placed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth:&lt;/strong&gt; Used to check user authentication before placing orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The other components in the architecture are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NGINX server:&lt;/strong&gt; Acts as the API gateway, reverse proxy, and load balancer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NATS broker:&lt;/strong&gt; &lt;a href="https://nats.io/"&gt;Nats.io&lt;/a&gt; is a messaging platform used to build distributed systems. Here we'll use it to facilitate communication between different services by publishing messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll dive into each individual component in later parts of this series, but I've tried to keep the services as minimal and simple as possible and put the main focus on the organisation and orchestration part of the entire microservices application.&lt;br&gt;
So, you'll notice that the functionality offered by each service is not very sophisticated, but it gets the idea across.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Docker, docker-compose&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is it for the introduction. The next part onwards we'll get our hands dirty with the code.&lt;br&gt;
I hope you'll enjoy this series and learn something new.&lt;/p&gt;

&lt;p&gt;Feel free to post any questions you have in the comments below.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>microservices</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Who is a good communicator?</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Tue, 19 Jul 2022 16:22:20 +0000</pubDate>
      <link>https://forem.com/sainig/who-is-a-good-communicator-2hp2</link>
      <guid>https://forem.com/sainig/who-is-a-good-communicator-2hp2</guid>
      <description>&lt;p&gt;I'm sure everyone will agree that good communication skills are very important, and not just in professional life but in every aspect of life. But rarely do I see someone describing what it actually means by good, or even great, communication skills. Often I feel people misunderstand the true meaning of good communication skills.&lt;br&gt;
So I thought maybe I'll share my take on this with you folks. Feel free to share your views in the comments, make corrections in the article, and add what you think I might have missed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The myth!
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good grammar/vocabulary:&lt;/strong&gt; Many people I've had the pleasure of dealing with or even work with think that people who have good grammar knowledge or who often use fancy multi-syllable words in their sentences are really good communicators. I always struggle to understand big words until I hear them quite a few times and do multiple google searches for meanings and usage examples. Sure, it's always good to have impeccable grammar and vocabulary if you're in a spelling bee, but not everyone can digest them easily. And to be honest, it's not even that important, as long as people get the point you're trying to make.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick responses:&lt;/strong&gt; Let me say this straightaway - it is important to respond quickly to emails, messages, even if it is just an acknowledgement saying you'll get back to them with an answer. But the belief that people who respond quickly are good at communication is definitely not true. Some even try to show off this skill and enforce it on others around them. Such replies, in most cases, end up being educated guesses at best and don't tend to be very well informed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incorrect communication platform:&lt;/strong&gt; This bothers me the most out of all the points mentioned here. People follow and endorse such bad practices of calling an in-person meeting for the most trivial tasks which could have easily been communicated in a written format. Or sometimes when people talk about a mission critical thing over a phone call, which should definitely have been an email to the whole team, or possibly even a meeting. Imagine going to JSConf and one of the presenters just refuses to talk and has big blocks of text on every slide, not very likeable, right?&lt;/p&gt;

&lt;p&gt;I did many mistakes in the past, but I continuously had this feeling bothering me that even the simplest of my conversations (both written and verbal) were missing something. Somehow, I was repeating myself too many times, not getting my point across, or having too many calls to clear up little work items.&lt;br&gt;
I slowly realised what I was doing wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The truth!
&lt;/h2&gt;

&lt;p&gt;While I agree not all points I mentioned above are bad to have if you want to improve your communication skills, but those points alone can never be sufficient. I'll share some points, habits, I think are super important if you want to be a good communicator. This is most definitely not an exhaustive list so feel free to add more points in the comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplify things.&lt;/strong&gt; This should be the top priority if you want to convey your message effectively and avoid any misunderstandings or even worse, conflicts. If you can break down a complex concept into simpler terms then you're much more likely to convince make your message easy to understand and remember.&lt;br&gt;
Consider this, if you can't convince a toddler to not put the lego man's head into their mouth for the millionth time, then you need to work on your communication skills. Okay, I get it, your task will not always be so close to impossible because in a professional setting you're not always talking to toddlers, so it's equally important to identify your audience and try to talk on their level, and make it easy for them to understand. Which brings me to the next skill...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have Empathy.&lt;/strong&gt; Many times I got frustrated at people for not getting what I was trying to tell or ask them, until I realised that not everyone has the same context as me, or is on the same level of intellect/experience as me. You can try to put yourself in their shoes to better understand why your point is not getting through to them. Who knows, you might even learn a thing or two by doing so. (has happened to me on multiple occasions)&lt;br&gt;
Plus people are more likely to listen closely and be more willing to indulge once they feel you understand their side of things as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Being polite&lt;/strong&gt; is one of those habits that's not easy to cultivate but goes a long way once you do so. If you're impolite or rude as a communicator then all the knowledge and skill in the world won't help your cause, because people won't even listen to you. On the flip side, one way of showing politeness is to listen and not interrupt when others are talking. Listening is a huge part of being a good communicator that many people miss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be transparent and proactive.&lt;/strong&gt; This holds true mostly when you're dealing with someone in a more formal setting. The other person will always appreciate you more if you're transparent with them and let them know of any unforeseen circumstances without them reaching out to you and specifically asking you about it. For example, if you're working with a client on a project and due to some newfound information or an unanticipated issue you have to bump up the story points on a ticket. The clients will be much happier if you proactively inform them about the situation at hand.&lt;/p&gt;

&lt;p&gt;These habits and tips have proved very valuable to me in my daily life. People find me easy to trust whenever I commit to something, and I no longer face the problems I mentioned earlier. So that's a win-win for everyone.&lt;/p&gt;

&lt;p&gt;Would love to hear your take on this.&lt;/p&gt;

&lt;p&gt;Cheers! 🤘&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>productivity</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>How to be better at new feature planning?</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Thu, 23 Jun 2022 14:06:46 +0000</pubDate>
      <link>https://forem.com/sainig/how-to-be-better-at-new-feature-planning-168f</link>
      <guid>https://forem.com/sainig/how-to-be-better-at-new-feature-planning-168f</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR - Our team is struggling with good technical analysis and planning for new features added into the product, so we need some ideas to help refine our process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whenever there's a new feature or a big enhancement to be added into the product, many times we struggle with efficient analysis and planning. This in turn messes up the estimations, and we end up scrambling at the end of sprints either shuffling tickets around or stretching our work hours.&lt;/p&gt;

&lt;p&gt;What I've suggested as a good starting point is to have a set of questions written down that cover the basic stuff common to most features or any new work in general. So, for any new feature request coming in from the clients, if we manage to get answers to these questions then at-least we have a good understanding of the LOE that's needed to get the work done, and also ease up the breakdown of big features into smaller tasks.&lt;/p&gt;

&lt;p&gt;The clients thoroughly cover the business aspect of the requirements. We need some ideas to get better at the technical side of things. I've felt many times that during planning we are left wondering what should we do during planning, and it all ends up being a wild goose chase. This is the number one problem we want to address.&lt;/p&gt;

&lt;p&gt;Also, how much time do you guys usually put into planning a new feature or a module. Eg: if at first glance, something looks like 3-4 days worth of work, than I think it's a good idea to put aside 2-3 hours where we can just brainstorm and think about all the teeny tiny details.&lt;/p&gt;

&lt;p&gt;One last question, is it a good idea to have everyone on the team sit down during the planning meeting?&lt;/p&gt;

&lt;p&gt;Thanks a lot in advance.&lt;/p&gt;

</description>
      <category>help</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to use custom express server with Botkit v4 (Slack bot)?</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Mon, 30 Nov 2020 11:02:56 +0000</pubDate>
      <link>https://forem.com/sainig/how-to-use-custom-express-server-with-botkit-v4-slack-bot-4ij2</link>
      <guid>https://forem.com/sainig/how-to-use-custom-express-server-with-botkit-v4-slack-bot-4ij2</guid>
      <description>&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/65070227/how-to-use-botkit-v4-with-custom-express-server-for-slack-bot"&gt;https://stackoverflow.com/questions/65070227/how-to-use-botkit-v4-with-custom-express-server-for-slack-bot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please help me with the above question&lt;/p&gt;

</description>
      <category>help</category>
      <category>slack</category>
      <category>botkit</category>
    </item>
    <item>
      <title>Help needed: Open source react component</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Sun, 19 Jul 2020 10:22:50 +0000</pubDate>
      <link>https://forem.com/sainig/help-needed-open-source-react-component-486m</link>
      <guid>https://forem.com/sainig/help-needed-open-source-react-component-486m</guid>
      <description>&lt;p&gt;Hi fellow DEVs 👋,&lt;br&gt;
A while ago, I created a basic react component, a wrapper for some multi step flows. This was my first ever react component that I wrote in an effort to learn and understand react better.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I &lt;del&gt;want&lt;/del&gt; need some help with the functionality where user is allowed to call some custom method/actions (synchronous or asynchronous) before proceeding to the next step, and go to next step/show error based on the user method response.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the component about?
&lt;/h2&gt;

&lt;p&gt;It is a dynamic, multi-step progress indicator with navigation buttons to move between steps. Optionally you could have some basic validation when proceeding to the next step.&lt;br&gt;
It has nice little animations and ZERO dependencies (till now).&lt;br&gt;
Excited? &lt;a href="https://www.npmjs.com/package/react-step-progress"&gt;Go check it out&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I need help with?
&lt;/h2&gt;

&lt;p&gt;I wanted to allow people to call their own custom methods, either synchronous or asynchronous, before proceeding to the next step. Right now, I have an optional &lt;code&gt;prop&lt;/code&gt; to allow for custom validation to be performed, but that is very naive as the validation function must have a return type of boolean, and no error message is shown.&lt;br&gt;
Ideally, I would like someone to help me achieve this but if you'd like to raise a PR that's fine too 😄, I can't seem to plan the whole thing very well&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get started?
&lt;/h2&gt;

&lt;p&gt;I already have an &lt;a href="https://github.com/saini-g/react-step-progress/issues/5"&gt;issue&lt;/a&gt; in the Github repo.&lt;br&gt;
Hit me up in the DEV chat or Discord(username: saini-g#3132) if you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  How else can I help?
&lt;/h2&gt;

&lt;p&gt;Any suggestions, PRs, ideas, help with documentation would also be nice.&lt;/p&gt;

&lt;p&gt;Thanks.&lt;/p&gt;

</description>
      <category>help</category>
      <category>contributorswanted</category>
      <category>react</category>
      <category>opensource</category>
    </item>
    <item>
      <title>React Native android build failure</title>
      <dc:creator>Gaurav Saini</dc:creator>
      <pubDate>Sat, 11 Jul 2020 07:03:47 +0000</pubDate>
      <link>https://forem.com/sainig/react-native-android-build-failure-50ge</link>
      <guid>https://forem.com/sainig/react-native-android-build-failure-50ge</guid>
      <description>&lt;p&gt;Hey folks,&lt;br&gt;
I'm struggling with building a react native project for android and need some help.&lt;br&gt;
When I run the build command (./gradlew bundleRelease) from the &lt;code&gt;&amp;lt;project_root&amp;gt;/android&lt;/code&gt; directory I get an error (as shown below) saying that I haven't accepted the licenses for the android SDK and I need to do so in order to build the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7bgAdo4b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/frvw9szkjoojvyquwdk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7bgAdo4b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/frvw9szkjoojvyquwdk0.png" alt="1-android-build-error" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And when (after some googling) I ran the accept licenses command from the SDK root directory, I get another error (as shown below)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c3C9K4QY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/yampztd00vij7rqhsj0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c3C9K4QY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/yampztd00vij7rqhsj0g.png" alt="2-accept-licenses-error" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It might be worth pointing out that I'm essentially reviving a very old project that I had the source code for, so the Android Studio, Android SDK and everything else is freshly installed on my system.&lt;/p&gt;

&lt;p&gt;Thanks in advance for all the help!&lt;/p&gt;

</description>
      <category>help</category>
      <category>reactnative</category>
      <category>android</category>
    </item>
  </channel>
</rss>
